Multi-Touch-Bewegungen

Compose ausprobieren
Jetpack Compose ist das empfohlene UI-Toolkit für Android. Informationen zum Verwenden von Touchbedienung und Eingabe in Compose

Bei einer Multitouch-Geste tippen mehrere Touchpunkte (Finger) gleichzeitig auf den Bildschirm. In diesem Dokument wird beschrieben, wie Touch-Gesten erkannt werden, die mehrere Touch-Stifte umfassen.

Mehrere Zeiger verfolgen

Wenn mehrere Touchstifte gleichzeitig auf das Display tippen, generiert das System die folgenden Touch-Ereignisse:

  • ACTION_DOWN: Wird gesendet, wenn der erste Zeiger auf das Display tippt. Dadurch wird die Geste gestartet. Die Pointerdaten für diesen Pointer befinden sich immer an Index 0 in der MotionEvent.
  • ACTION_POINTER_DOWN: Wird gesendet, wenn nach dem ersten Zeiger weitere Zeiger auf dem Bildschirm erscheinen. Mit getActionIndex() können Sie den Index des Zeigers abrufen, der gerade nach unten gegangen ist.
  • ACTION_MOVE: Wird gesendet, wenn sich eine Geste ändert, an der beliebig viele Touchbalken beteiligt sind.
  • ACTION_POINTER_UP: Wird gesendet, wenn ein nicht primärer Zeiger nach oben bewegt wird. Mit getActionIndex() können Sie den Index des gerade erstellten Zeigers abrufen.
  • ACTION_UP: Wird gesendet, wenn der letzte Cursor den Bildschirm verlässt.
  • ACTION_CANCEL: gibt an, dass die gesamte Geste, einschließlich aller Zeiger, abgebrochen wird.

Start- und Endgesten

Eine Geste besteht aus einer Reihe von Ereignissen, die mit einem ACTION_DOWN-Ereignis beginnen und entweder mit einem ACTION_UP- oder einem ACTION_CANCEL-Ereignis enden. Es kann immer nur eine Geste aktiv sein. Die Aktionen „NACH UNTEN“, „BEWEGEN“, „NACH OBEN“ und „ABBRECHEN“ gelten für die gesamte Geste. Ein Ereignis mit ACTION_MOVE kann beispielsweise eine Bewegung aller Mauszeiger in diesem Moment anzeigen.

Verweise im Blick behalten

Verwenden Sie den Index und die ID des Zeigers, um die Positionen der einzelnen Zeiger innerhalb eines MotionEvent im Blick zu behalten.

  • Index: Ein MotionEvent speichert Verweise in einem Array. Der Index eines Zeigers ist seine Position in diesem Array. Die meisten MotionEvent-Methoden verwenden den Zeigerindex anstelle der Zeiger-ID als Parameter.
  • ID: Jeder Zeiger hat eine ID-Zuordnung, die über Touch-Ereignisse hinweg erhalten bleibt, um einen einzelnen Zeiger während der gesamten Geste zu verfolgen.

Einzelne Zeiger werden innerhalb eines Bewegungsereignisses in einer nicht definierten Reihenfolge angezeigt. Der Index eines Cursors kann sich also von Ereignis zu Ereignis ändern, die Cursor-ID bleibt jedoch so lange konstant, wie der Cursor aktiv ist. Mit der Methode getPointerId() können Sie die ID eines Cursors abrufen, um den Cursor bei allen nachfolgenden Bewegungsereignissen in einer Geste zu verfolgen. Verwenden Sie dann für aufeinanderfolgende Bewegungsereignisse die Methode findPointerIndex(), um den Zeigerindex für eine bestimmte Zeiger-ID in diesem Bewegungsereignis abzurufen. Beispiel:

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

Wenn Sie mehrere Touch-Cursor unterstützen möchten, können Sie alle aktiven Cursor mit ihren IDs zum jeweiligen ACTION_POINTER_DOWN- und ACTION_DOWN-Ereigniszeitpunkt im Cache speichern. Entfernen Sie die Verweise aus Ihrem Cache bei den Ereignissen ACTION_POINTER_UP und ACTION_UP. Diese im Cache gespeicherten IDs können hilfreich sein, um andere Ereignistypen korrekt zu verarbeiten. Wenn Sie beispielsweise ein ACTION_MOVE-Ereignis verarbeiten, können Sie den Index für jede im Cache gespeicherte aktive Zeiger-ID ermitteln, die Koordinaten des Zeigers mithilfe der Funktionen getX() und getY() abrufen und diese Koordinaten dann mit den im Cache gespeicherten Koordinaten vergleichen, um herauszufinden, welche Zeiger sich bewegt haben.

Verwenden Sie die Funktion getActionIndex() nur mit ACTION_POINTER_UP- und ACTION_POINTER_DOWN-Ereignissen. Verwenden Sie diese Funktion nicht mit ACTION_MOVE-Ereignissen, da in diesem Fall immer 0 zurückgegeben wird.

MotionEvent-Aktionen abrufen

Verwenden Sie die Methode getActionMasked() oder die Kompatibilitätsversion MotionEventCompat.getActionMasked(), um die Aktion einer MotionEvent abzurufen. Im Gegensatz zur früheren Methode getAction() ist getActionMasked() für die Arbeit mit mehreren Zeigern konzipiert. Die Aktion wird ohne die Zeigerindizes zurückgegeben. Verwenden Sie für Aktionen mit einem gültigen Zeigerindex getActionIndex(), um den Index der mit der Aktion verknüpften Zeiger zurückzugeben, wie im folgenden Snippet gezeigt:

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 "";
}
Abbildung 1. Multi-Touch-Zeichenmuster.

Weitere Informationen

Weitere Informationen zu Eingabeereignissen finden Sie in den folgenden Referenzen: