Un gesto de varios toques se produce cuando varios punteros (dedos) presionan la pantalla al mismo tiempo. En este documento, se describe cómo detectar gestos que involucran varios punteros.
Cómo rastrear varios punteros
Cuando varios punteros presionan la pantalla al mismo tiempo, el sistema genera los siguientes eventos táctiles:
ACTION_DOWN
: Se envía cuando el primer puntero presiona la pantalla. Este evento comienza el gesto. Los datos del puntero para este puntero siempre están en el índice0
deMotionEvent
.ACTION_POINTER_DOWN
: Se envía cuando los punteros adicionales ingresan a la pantalla después del primero. Puedes obtener el índice del puntero que se acaba de bajar mediantegetActionIndex()
.ACTION_MOVE
: Se envía cuando se produce un cambio en un gesto que involucra cualquier cantidad de punteros.ACTION_POINTER_UP
: Se envía cuando un puntero que no es principal va hacia arriba. Puedes obtener el índice del puntero que acaba de subir mediantegetActionIndex()
.ACTION_UP
: Se envía cuando el último puntero sale de la pantalla.ACTION_CANCEL
: Indica que se canceló todo el gesto, incluidos todos los punteros.
Gestos de inicio y finalización
Un gesto es una serie de eventos que comienzan con un evento ACTION_DOWN
y terminan con un evento ACTION_UP
o ACTION_CANCEL
. Hay un gesto activo a la vez. Las acciones DOWN, MOVE, UP y CANCEL se aplican a todo el gesto. Por ejemplo, un evento con ACTION_MOVE
puede indicar un movimiento para todos los punteros hacia abajo en ese momento.
Haz un seguimiento de los punteros
Usa el índice y el ID del puntero para realizar un seguimiento de las posiciones de los punteros individuales dentro de un MotionEvent
.
- Índice: Un
MotionEvent
almacena la información del puntero en un array. El índice de un puntero es su posición dentro de este array. La mayoría de los métodosMotionEvent
toman el índice del puntero como parámetro, en lugar del ID del puntero. - ID: Cada puntero también tiene una asignación de ID que se mantiene persistente en los eventos táctiles para permitir el seguimiento de un puntero individual en todo el gesto.
Los punteros individuales aparecen dentro de un evento de movimiento en un orden indefinido. Por lo tanto, el índice de un puntero puede cambiar de un evento al siguiente, pero se garantiza que el ID del puntero de un puntero permanecerá constante mientras el puntero permanezca activo. Usa el método getPointerId()
para obtener el ID de un puntero y hacer un seguimiento del puntero en todos los eventos de movimiento posteriores de un gesto. Luego, para eventos de movimiento sucesivos, usa el método findPointerIndex()
a fin de obtener el índice del puntero para un ID de puntero determinado en ese evento de movimiento.
Por ejemplo:
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); ... }
Para admitir varios punteros táctiles, puedes almacenar en caché todos los punteros activos con sus IDs a la hora individual del evento ACTION_POINTER_DOWN
y ACTION_DOWN
. Quita los punteros de la caché en
sus eventos ACTION_POINTER_UP
y ACTION_UP
. Estos IDs almacenados en caché te pueden resultar útiles para controlar otros eventos de acción de forma correcta. Por ejemplo, cuando proceses un evento ACTION_MOVE
, busca el índice para cada ID de puntero activo almacenado en caché, recupera las coordenadas del puntero con las funciones getX()
y getY()
, y compáralas con las almacenadas en caché para descubrir qué punteros se movieron.
Usa la función getActionIndex()
solo con los eventos ACTION_POINTER_UP
y ACTION_POINTER_DOWN
. No uses esta función con eventos ACTION_MOVE
, ya que siempre muestra 0
.
Recuperar MotionEvent
acciones
Usa el método getActionMasked()
o la versión de compatibilidad MotionEventCompat.getActionMasked()
para recuperar la acción de un MotionEvent
. A diferencia del método getAction()
anterior, getActionMasked()
está diseñado para funcionar con varios punteros. Muestra la acción sin los índices del puntero. En el caso de las acciones con un índice de puntero válido, usa getActionIndex()
para mostrar el índice de los punteros asociados con la acción, como se muestra en el siguiente fragmento:
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 ""; }
Recursos adicionales
Para obtener más información relacionada con los eventos de entrada, consulta las siguientes referencias:
- Descripción general de eventos de entrada
- Descripción general de sensores
- Cómo hacer que una vista personalizada sea interactiva
- Arrastrar y ajustar