Suivre les mouvements tactiles et du curseur

Essayer Compose
Jetpack Compose est le kit d'outils d'interface utilisateur recommandé pour Android. Découvrez comment utiliser l'écran tactile et la saisie dans Compose.

Cette leçon explique comment suivre les mouvements dans les événements tactiles.

Un nouveau onTouchEvent() est déclenché avec un événement ACTION_MOVE chaque fois que la position, la pression ou la taille du contact tactile actuelle change. Comme décrit dans la section Détecter les gestes courants, tous ces événements sont enregistrés dans le paramètre MotionEvent de onTouchEvent().

Étant donné que le toucher par le doigt n'est pas toujours la forme d'interaction la plus précise, la détection des événements tactiles est souvent basée davantage sur le mouvement que sur un simple contact. Pour aider les applications à faire la distinction entre les gestes basés sur le mouvement (comme le balayage) et les gestes sans mouvement (comme un simple geste), Android inclut la notion de pente tactile. La pente tactile correspond à la distance en pixels que l'utilisateur peut toucher avant que le geste ne soit interprété comme un geste basé sur le mouvement. Pour en savoir plus à ce sujet, consultez Gérer les événements tactiles dans un ViewGroup.

Il existe plusieurs façons de suivre les mouvements dans un geste, en fonction des besoins de votre application. Voici des exemples:

  • Positions de début et de fin d'un pointeur (par exemple, déplacement d'un objet à l'écran d'un point A vers un point B).
  • Direction dans laquelle le pointeur se déplace, telle que déterminée par les coordonnées X et Y.
  • Historique. Vous pouvez connaître la taille de l'historique d'un geste en appelant la méthode MotionEvent getHistorySize(). Vous pouvez ensuite obtenir les positions, les tailles, la durée et les pressions de chacun des événements historiques à l'aide des méthodes getHistorical<Value> de l'événement de mouvement. L'historique est utile pour afficher une trace du doigt de l'utilisateur, par exemple pour le dessin tactile. Pour en savoir plus, consultez la documentation de référence sur MotionEvent.
  • Vitesse du pointeur lorsqu'il se déplace sur l'écran tactile.

Consultez les ressources associées suivantes :

Suivre la vitesse

Vous pouvez effectuer un geste basé sur le mouvement en fonction de la distance ou de la direction du pointeur. Cependant, la vitesse est souvent un facteur déterminant pour suivre les caractéristiques d'un geste ou décider s'il a eu lieu. Pour faciliter le calcul de la vitesse, Android fournit la classe VelocityTracker. VelocityTracker vous aide à suivre la vitesse des événements tactiles. Cela est utile pour les gestes dont la vitesse fait partie des critères du geste, comme un glissement d'un geste vif.

Voici un exemple qui illustre l'objectif des méthodes dans l'API VelocityTracker:

Kotlin

private const val DEBUG_TAG = "Velocity"

class MainActivity : Activity() {
    private var mVelocityTracker: VelocityTracker? = null

    override fun onTouchEvent(event: MotionEvent): Boolean {

        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                // Reset the velocity tracker back to its initial state.
                mVelocityTracker?.clear()
                // If necessary, retrieve a new VelocityTracker object to watch
                // the velocity of a motion.
                mVelocityTracker = mVelocityTracker ?: VelocityTracker.obtain()
                // Add a user's movement to the tracker.
                mVelocityTracker?.addMovement(event)
            }
            MotionEvent.ACTION_MOVE -> {
                mVelocityTracker?.apply {
                    val pointerId: Int = event.getPointerId(event.actionIndex)
                    addMovement(event)
                    // When you want to determine the velocity, call
                    // computeCurrentVelocity(). Then, call getXVelocity() and
                    // getYVelocity() to retrieve the velocity for each pointer
                    // ID.
                    computeCurrentVelocity(1000)
                    // Log velocity of pixels per second. It's best practice to
                    // use VelocityTrackerCompat where possible.
                    Log.d("", "X velocity: ${getXVelocity(pointerId)}")
                    Log.d("", "Y velocity: ${getYVelocity(pointerId)}")
                }
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                // Return a VelocityTracker object back to be re-used by others.
                mVelocityTracker?.recycle()
                mVelocityTracker = null
            }
        }
        return true
    }
}

Java

public class MainActivity extends Activity {
    private static final String DEBUG_TAG = "Velocity";
        ...
    private VelocityTracker mVelocityTracker = null;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int index = event.getActionIndex();
        int action = event.getActionMasked();
        int pointerId = event.getPointerId(index);

        switch(action) {
            case MotionEvent.ACTION_DOWN:
                if(mVelocityTracker == null) {
                    // Retrieve a new VelocityTracker object to watch the
                    // velocity of a motion.
                    mVelocityTracker = VelocityTracker.obtain();
                }
                else {
                    // Reset the velocity tracker back to its initial state.
                    mVelocityTracker.clear();
                }
                // Add a user's movement to the tracker.
                mVelocityTracker.addMovement(event);
                break;
            case MotionEvent.ACTION_MOVE:
                mVelocityTracker.addMovement(event);
                // When you want to determine the velocity, call
                // computeCurrentVelocity(). Then call getXVelocity() and
                // getYVelocity() to retrieve the velocity for each pointer ID.
                mVelocityTracker.computeCurrentVelocity(1000);
                // Log velocity of pixels per second. It's best practice to use
                // VelocityTrackerCompat where possible.
                Log.d("", "X velocity: " + mVelocityTracker.getXVelocity(pointerId));
                Log.d("", "Y velocity: " + mVelocityTracker.getYVelocity(pointerId));
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                // Return a VelocityTracker object back to be re-used by others.
                mVelocityTracker.recycle();
                break;
        }
        return true;
    }
}

Utiliser la capture du pointeur

Certaines applications, telles que les jeux, le bureau à distance et les clients de virtualisation, peuvent bénéficier du contrôle du pointeur de la souris. La capture du pointeur est une fonctionnalité disponible sur Android 8.0 (niveau d'API 26) ou version ultérieure. Elle fournit cette commande en fournissant tous les événements de souris dans une vue ciblée de votre application.

Capture de pointeur de requête

Une vue de votre application ne peut demander la capture du pointeur que lorsque la hiérarchie des vues qui la contient est active. Pour cette raison, demandez la capture du pointeur en cas d'action utilisateur spécifique sur la vue, par exemple lors d'un événement onClick() ou dans le gestionnaire d'événements onWindowFocusChanged() de votre activité.

Pour demander la capture du pointeur, appelez la méthode requestPointerCapture() sur la vue. L'exemple de code suivant montre comment demander la capture du pointeur lorsque l'utilisateur clique sur une vue:

Kotlin

fun onClick(view: View) {
    view.requestPointerCapture()
}

Java

@Override
public void onClick(View view) {
    view.requestPointerCapture();
}

Une fois que la requête de capture du pointeur aboutit, Android appelle onPointerCaptureChange(true). Le système transmet les événements de souris à la vue sélectionnée dans votre application, à condition qu'elle se trouve dans la même hiérarchie des vues que la vue qui a demandé la capture. D'autres applications cessent de recevoir les événements de souris jusqu'à ce que la capture soit publiée, y compris les événements ACTION_OUTSIDE. Android diffuse normalement des événements de pointeur provenant de sources autres que la souris, mais celui-ci n'est plus visible.

Gérer les événements de pointeur capturés

Une fois qu'une vue a acquis la capture du pointeur, Android diffuse les événements de souris. La vue sélectionnée peut gérer les événements en effectuant l'une des tâches suivantes:

L'exemple de code suivant montre comment implémenter onCapturedPointerEvent(MotionEvent):

Kotlin

override fun onCapturedPointerEvent(motionEvent: MotionEvent): Boolean {
    // Get the coordinates required by your app.
    val verticalOffset: Float = motionEvent.y
    // Use the coordinates to update your view and return true if the event is
    // successfully processed.
    return true
}

Java

@Override
public boolean onCapturedPointerEvent(MotionEvent motionEvent) {
  // Get the coordinates required by your app.
  float verticalOffset = motionEvent.getY();
  // Use the coordinates to update your view and return true if the event is
  // successfully processed.
  return true;
}

L'exemple de code suivant montre comment enregistrer un OnCapturedPointerListener:

Kotlin

myView.setOnCapturedPointerListener { view, motionEvent ->
    // Get the coordinates required by your app.
    val horizontalOffset: Float = motionEvent.x
    // Use the coordinates to update your view and return true if the event is
    // successfully processed.
    true
}

Java

myView.setOnCapturedPointerListener(new View.OnCapturedPointerListener() {
  @Override
  public boolean onCapturedPointer (View view, MotionEvent motionEvent) {
    // Get the coordinates required by your app.
    float horizontalOffset = motionEvent.getX();
    // Use the coordinates to update your view and return true if the event is
    // successfully processed.
    return true;
  }
});

Que vous utilisiez une vue personnalisée ou que vous enregistriez un écouteur, votre vue reçoit un MotionEvent avec des coordonnées de pointeur qui spécifient les mouvements relatifs tels que les deltas X ou Y, semblables aux coordonnées fournies par un trackball. Vous pouvez récupérer les coordonnées à l'aide de getX() et getY().

Capture du pointeur de libération

La vue de votre application peut libérer la capture du pointeur en appelant releasePointerCapture(), comme illustré dans l'exemple de code suivant:

Kotlin

override fun onClick(view: View) {
    view.releasePointerCapture()
}

Java

@Override
public void onClick(View view) {
    view.releasePointerCapture();
}

Le système peut retirer la capture de la vue sans que vous ayez explicitement appelé releasePointerCapture(), généralement parce que la hiérarchie des vues contenant la vue capturée par les requêtes perd son focus.