Cómo manejar los gestos multitáctiles

Prueba el método de Compose
Jetpack Compose es el kit de herramientas de IU recomendado para Android. Aprende a usar el control táctil y la entrada en Compose.

Un gesto multitáctil se produce cuando varios punteros (dedos) presionan la pantalla en al mismo tiempo. En este documento, se describe cómo detectar gestos que involucran múltiples 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: que se envía cuando el primer puntero presiona la pantalla. Este evento comienza el gesto. El Los datos del puntero para este puntero siempre están en el índice 0 de MotionEvent
  • ACTION_POINTER_DOWN: que se envía cuando los punteros adicionales ingresan a la pantalla después del primero. Puedes obtener el índice del puntero que acaba de bajar con getActionIndex()
  • ACTION_MOVE: que se envía cuando se produce un cambio en un gesto, que involucra cualquier cantidad de de seguridad.
  • ACTION_POINTER_UP: que se envía cuando un puntero no principal sube. Puedes obtener el índice del que acaba de subir con getActionIndex().
  • ACTION_UP: que 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 ACTION_DOWN que termina con ACTION_UP o ACTION_CANCEL evento. Hay un gesto activo a la vez. El las acciones hacia ABAJO, MOVER, ARRIBA y CANCELAR se aplican a todo el gesto. Por ejemplo, un un evento con ACTION_MOVE puede indicar un movimiento para todos los punteros en ese momento.

Haz un seguimiento de los punteros

Usa el índice y el ID del puntero para hacer un seguimiento de los punteros individuales posiciones dentro de un MotionEvent.

  • Índice: un MotionEvent almacena puntero información en un array. El índice de un puntero es su posición dentro de . La mayoría de los métodos MotionEvent toman el índice del puntero como un 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 a otro, pero el ID del puntero de un puntero permanecerá constante mientras el puntero activo. Usa el getPointerId() método para obtener el ID de un puntero y hacer un seguimiento del puntero en todas las de movimiento en un gesto. Luego, para eventos de movimiento sucesivos, usa la función findPointerIndex() para 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 en su ACTION_POINTER_DOWN individual Hora del evento: ACTION_DOWN. Quita los punteros de tu caché en sus eventos ACTION_POINTER_UP y ACTION_UP. Quizás estos IDs almacenados en caché son útiles para gestionar otros eventos de acción correctamente. Para Por ejemplo, cuando proceses un evento ACTION_MOVE, busca el índice del de cada ID de puntero activo almacenado en caché, recupera las coordenadas del puntero con el getX() y getY() y, luego, compara estas coordenadas con las coordenadas en caché para descubrir qué punteros se movieron.

Usa la función getActionIndex() con ACTION_POINTER_UP y ACTION_POINTER_DOWN eventos solamente. No uses esta función con eventos ACTION_MOVE, ya que Siempre muestra 0.

Recuperar acciones de MotionEvent

Usa el getActionMasked() o la versión de compatibilidad MotionEventCompat.getActionMasked() para recuperar la acción de un MotionEvent. A diferencia del anterior getAction() método, getActionMasked() está diseñado para trabajar con varias de seguridad. Devuelve la acción sin los índices del puntero. Para acciones con una í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 "";
}
Figura 1: Dibujo multitáctil o patrones.

Recursos adicionales

Para obtener más información relacionada con los eventos de entrada, consulta los siguientes vínculos: referencias: