Gestire i gesti multi-touch

Prova il metodo Scrivi
Jetpack Compose è il toolkit consigliato per la UI per Android. Scopri come utilizzare il tocco e l'input in Compose.

Un gesto multi-touch si verifica quando più puntatori (dita) toccano lo schermo contemporaneamente. Questo documento descrive come rilevare gesti che coinvolgono più puntatori.

Monitora più cursori

Quando più puntatori toccano lo schermo contemporaneamente, il sistema genera i seguenti eventi touch:

  • ACTION_DOWN: inviato quando il primo puntatore tocca lo schermo. Il gesto viene avviato. I dati per questo puntatore si trovano sempre nell'indice 0 nella MotionEvent.
  • ACTION_POINTER_DOWN: inviato quando i puntatori aggiuntivi entrano nella schermata dopo il primo. Puoi ottenere l'indice del puntatore appena abbassato utilizzando getActionIndex().
  • ACTION_MOVE: inviato quando si verifica una modifica in un gesto, che coinvolge un numero qualsiasi di puntatori.
  • ACTION_POINTER_UP: inviato quando un puntatore non principale sale. Puoi ottenere l'indice del puntatore appena aumentato utilizzando getActionIndex().
  • ACTION_UP: inviato quando l'ultimo puntatore esce dalla schermata.
  • ACTION_CANCEL: indica che l'intero gesto, inclusi tutti i cursori, è stato annullato.

Gesti di inizio e fine

Un gesto è una serie di eventi che iniziano con un evento ACTION_DOWN e terminano con un evento ACTION_UP o ACTION_CANCEL. C'è un gesto attivo alla volta. Le azioni GIÙ, SPOSTA, SU e ANNULLA vengono applicate all'intero gesto. Ad esempio, un evento con ACTION_MOVE può indicare un movimento per tutti i puntatori verso il basso in quel momento.

Tieni traccia dei cursori

Utilizza l'indice e l'ID del puntatore per tenere traccia delle posizioni dei singoli cursori all'interno di un MotionEvent.

  • Indice: un MotionEvent archivia le informazioni del puntatore in un array. L'indice di un puntatore è la sua posizione all'interno di questo array. La maggior parte dei metodi MotionEvent utilizza l'indice del puntatore come parametro, anziché l'ID del puntatore.
  • ID: ogni puntatore ha anche una mappatura ID che rimane permanente tra gli eventi touch per consentire il monitoraggio di un singolo puntatore nell'intero gesto.

I singoli puntatori vengono visualizzati all'interno di un evento di movimento in un ordine indefinito. Pertanto, l'indice di un puntatore può cambiare da un evento all'altro, ma è garantito che l'ID di un puntatore rimanga costante finché il puntatore rimane attivo. Utilizza il metodo getPointerId() per ottenere l'ID di un puntatore in modo da monitorarlo in tutti gli eventi di movimento successivi in un gesto. Quindi, per gli eventi di movimento successivi, utilizza il metodo findPointerIndex() per ottenere l'indice del puntatore per un determinato ID puntatore in quell'evento di movimento. Ecco alcuni esempi:

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);
    ...
}

Per supportare più puntatori touch, puoi memorizzare nella cache tutti i puntatori attivi con i relativi ID nei rispettivi orari degli eventi ACTION_POINTER_DOWN e ACTION_DOWN. Rimuovi i puntatori dalla cache in corrispondenza degli eventi ACTION_POINTER_UP e ACTION_UP. Questi ID memorizzati nella cache potrebbero essere utili per gestire correttamente altri eventi di azioni. Ad esempio, durante l'elaborazione di un evento ACTION_MOVE, trova l'indice per ogni ID puntatore attivo memorizzato nella cache, recupera le coordinate del puntatore utilizzando le funzioni getX() e getY(), quindi confronta queste coordinate con quelle memorizzate nella cache per scoprire quali puntatori sono stati spostati.

Utilizza la funzione getActionIndex() solo con gli eventi ACTION_POINTER_UP e ACTION_POINTER_DOWN. Non utilizzare questa funzione con gli eventi ACTION_MOVE, poiché restituisce sempre 0.

Recupera MotionEvent azioni

Utilizza il metodo getActionMasked() o la versione di compatibilità MotionEventCompat.getActionMasked() per recuperare l'azione di un MotionEvent. A differenza del metodo getAction() precedente, getActionMasked() è progettato per funzionare con più puntatori. Restituisce l'azione senza gli indici del puntatore. Per le azioni con un indice di puntatore valido, utilizza getActionIndex() per restituire l'indice dei puntatori associati all'azione, come mostrato nello snippet seguente:

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. Pattern di disegno multi-touch.

Risorse aggiuntive

Per ulteriori informazioni relative agli eventi di input, consulta i seguenti riferimenti: