Un geste multipoint consiste à appuyer simultanément sur l'écran avec plusieurs pointeurs (doigts). Ce document explique comment détecter les gestes impliquant plusieurs pointeurs.
Suivre plusieurs pointeurs
Lorsque plusieurs pointeurs appuient sur l'écran en même temps, le système génère les événements tactiles suivants:
ACTION_DOWN
: envoyé lorsque le premier pointeur appuie sur l'écran. Le geste commence. Les données de pointeur de ce pointeur se trouvent toujours à l'index0
dansMotionEvent
.ACTION_POINTER_DOWN
: envoyé lorsque des pointeurs supplémentaires entrent dans l'écran après le premier. Vous pouvez obtenir l'index du pointeur qui vient de descendre à l'aide degetActionIndex()
.ACTION_MOVE
: envoyé lorsqu'un changement se produit dans un geste, impliquant un nombre quelconque de pointeurs.ACTION_POINTER_UP
: envoyé lorsqu'un pointeur non principal monte. Vous pouvez obtenir l'index du pointeur qui vient d'augmenter à l'aide degetActionIndex()
.ACTION_UP
: envoyé lorsque le dernier pointeur quitte l'écran.ACTION_CANCEL
: indique que l'ensemble du geste, y compris tous les pointeurs, est annulé.
Gestes de début et de fin
Un geste est une série d'événements commençant par un événement ACTION_DOWN
et se terminant par un événement ACTION_UP
ou ACTION_CANCEL
. Un seul geste est actif à la fois. Les actions BAS, DÉPLACER, HAUT et ANNULER s'appliquent à l'ensemble du geste. Par exemple, un événement avec ACTION_MOVE
peut indiquer un mouvement pour tous les pointeurs vers le bas à ce moment-là.
Suivre les pointeurs
Utilisez l'index et l'ID du pointeur pour suivre les positions individuelles des pointeurs dans un MotionEvent
.
- Index: un
MotionEvent
stocke des informations de pointeur dans un tableau. L'index d'un pointeur correspond à sa position dans ce tableau. La plupart des méthodesMotionEvent
utilisent l'index du pointeur comme paramètre, plutôt que l'ID du pointeur. - ID: chaque pointeur dispose également d'une mise en correspondance d'ID qui reste persistante pour tous les événements tactiles afin de permettre le suivi d'un pointeur individuel tout au long du geste.
Les pointeurs individuels apparaissent dans un événement de mouvement dans un ordre indéterminé. Par conséquent, l'indice d'un pointeur peut changer d'un événement à l'autre, mais l'ID du pointeur reste constant tant qu'il est actif. Utilisez la méthode getPointerId()
pour obtenir l'ID d'un pointeur afin de le suivre dans tous les événements de mouvement ultérieurs d'un geste. Ensuite, pour les événements de mouvement successifs, utilisez la méthode findPointerIndex()
pour obtenir l'indice du pointeur pour un ID de pointeur donné dans cet événement de mouvement.
Exemple :
Kotlin
private var mActivePointerId: Int = 0 override fun onTouchEvent(event: MotionEvent): Boolean { ... // Get the pointer ID. mActivePointerId = event.getPointerId(0) // ... Many touch events later... // Use the pointer ID to find the index of the active pointer // and fetch its position. val (x: Float, y: Float) = event.findPointerIndex(mActivePointerId).let { pointerIndex -> // Get the pointer's current position. event.getX(pointerIndex) to event.getY(pointerIndex) } ... }
Java
private int mActivePointerId; public boolean onTouchEvent(MotionEvent event) { ... // Get the pointer ID. mActivePointerId = event.getPointerId(0); // ... Many touch events later... // Use the pointer ID to find the index of the active pointer // and fetch its position. int pointerIndex = event.findPointerIndex(mActivePointerId); // Get the pointer's current position. float x = event.getX(pointerIndex); float y = event.getY(pointerIndex); ... }
Pour prendre en charge plusieurs pointeurs tactiles, vous pouvez mettre en cache tous les pointeurs actifs avec leurs ID au moment de leur événement ACTION_POINTER_DOWN
et ACTION_DOWN
respectifs. Supprimez les pointeurs de votre cache lors de leurs événements ACTION_POINTER_UP
et ACTION_UP
. Ces ID mis en cache peuvent vous aider à gérer correctement d'autres événements d'action. Par exemple, lors du traitement d'un événement ACTION_MOVE
, recherchez l'index de chaque ID de pointeur actif mis en cache, récupérez les coordonnées du pointeur à l'aide des fonctions getX()
et getY()
, puis comparez ces coordonnées à vos coordonnées mises en cache pour découvrir quels pointeurs ont bougé.
Utilisez la fonction getActionIndex()
avec les événements ACTION_POINTER_UP
et ACTION_POINTER_DOWN
uniquement. N'utilisez pas cette fonction avec des événements ACTION_MOVE
, car elle renvoie toujours 0
.
Récupérer des actions MotionEvent
Utilisez la méthode getActionMasked()
ou la version de compatibilité MotionEventCompat.getActionMasked()
pour récupérer l'action d'un MotionEvent
. Contrairement à la méthode getAction()
précédente, getActionMasked()
est conçu pour fonctionner avec plusieurs pointeurs. Il renvoie l'action sans les indices de pointeur. Pour les actions avec un indice de pointeur valide, utilisez getActionIndex()
pour renvoyer l'indice des pointeurs associés à l'action, comme illustré dans l'extrait de code suivant:
Kotlin
val (xPos: Int, yPos: Int) = MotionEventCompat.getActionMasked(event).let { action -> Log.d(DEBUG_TAG, "The action is ${actionToString(action)}") // Get the index of the pointer associated with the action. MotionEventCompat.getActionIndex(event).let { index -> // The coordinates of the current screen contact, relative to // the responding View or Activity. MotionEventCompat.getX(event, index).toInt() to MotionEventCompat.getY(event, index).toInt() } } if (event.pointerCount > 1) { Log.d(DEBUG_TAG, "Multitouch event") } else { // Single touch event. Log.d(DEBUG_TAG, "Single touch event") } ... // Given an action int, returns a string description. fun actionToString(action: Int): String { return when (action) { MotionEvent.ACTION_DOWN -> "Down" MotionEvent.ACTION_MOVE -> "Move" MotionEvent.ACTION_POINTER_DOWN -> "Pointer Down" MotionEvent.ACTION_UP -> "Up" MotionEvent.ACTION_POINTER_UP -> "Pointer Up" MotionEvent.ACTION_OUTSIDE -> "Outside" MotionEvent.ACTION_CANCEL -> "Cancel" else -> "" } }
Java
int action = MotionEventCompat.getActionMasked(event); // Get the index of the pointer associated with the action. int index = MotionEventCompat.getActionIndex(event); int xPos = -1; int yPos = -1; Log.d(DEBUG_TAG,"The action is " + actionToString(action)); if (event.getPointerCount() > 1) { Log.d(DEBUG_TAG,"Multitouch event"); // The coordinates of the current screen contact, relative to // the responding View or Activity. xPos = (int)MotionEventCompat.getX(event, index); yPos = (int)MotionEventCompat.getY(event, index); } else { // Single touch event. Log.d(DEBUG_TAG,"Single touch event"); xPos = (int)MotionEventCompat.getX(event, index); yPos = (int)MotionEventCompat.getY(event, index); } ... // Given an action int, returns a string description public static String actionToString(int action) { switch (action) { case MotionEvent.ACTION_DOWN: return "Down"; case MotionEvent.ACTION_MOVE: return "Move"; case MotionEvent.ACTION_POINTER_DOWN: return "Pointer Down"; case MotionEvent.ACTION_UP: return "Up"; case MotionEvent.ACTION_POINTER_UP: return "Pointer Up"; case MotionEvent.ACTION_OUTSIDE: return "Outside"; case MotionEvent.ACTION_CANCEL: return "Cancel"; } return ""; }
Ressources supplémentaires
Pour en savoir plus sur les événements d'entrée, consultez les références suivantes:
- Présentation des événements d'entrée
- Présentation des capteurs
- Rendre une vue personnalisée interactive
- Faire glisser et redimensionner