Multi-Touch-Bewegungen

Funktion „Schreiben“ ausprobieren
Jetpack Compose ist das empfohlene UI-Toolkit für Android. Weitere Informationen

Eine Multi-Touch-Geste liegt vor, wenn mehrere Zeiger (Finger) gleichzeitig auf den Bildschirm tippen. In diesem Dokument wird beschrieben, wie Gesten erkannt werden, die mehrere Zeiger umfassen.

Mehrere Hinweise erfassen

Wenn mehrere Zeiger gleichzeitig auf den Bildschirm tippen, generiert das System die folgenden Touch-Ereignisse:

  • ACTION_DOWN: wird gesendet, wenn der erste Mauszeiger auf den Bildschirm tippt. Dadurch wird die Touch-Geste gestartet. Die Zeigerdaten für diesen Zeiger befinden sich immer bei Index 0 in MotionEvent.
  • ACTION_POINTER_DOWN: wird gesendet, wenn nach dem ersten zusätzlichen Mauszeiger auf dem Bildschirm erscheint. Sie können den Index des gerade gesunkenen Zeigers mit getActionIndex() abrufen.
  • ACTION_MOVE: wird gesendet, wenn bei einer Geste eine Änderung vorgenommen wird. Dabei kann eine beliebige Anzahl von Zeigern verwendet werden.
  • ACTION_POINTER_UP: wird gesendet, wenn ein nicht-primärer Cursor nach oben steigt. Sie können den Index des Zeigers, der gerade nach oben gestiegen ist, mit getActionIndex() abrufen.
  • ACTION_UP: Wird gesendet, wenn der letzte Mauszeiger den Bildschirm verlässt.
  • ACTION_CANCEL: Gibt an, dass die gesamte Touch-Geste einschließlich aller Mauszeiger abgebrochen wird.

Start- und End-Touch-Gesten

Eine Geste ist eine Reihe von Ereignissen, die mit einem ACTION_DOWN-Ereignis beginnen und mit einem ACTION_UP- oder ACTION_CANCEL-Ereignis endet. Es gibt jeweils eine aktive Geste. Die Aktionen UNTEN, VERSCHIEBEN, NACH OBEN und ABBRECHEN gelten für die gesamte Geste. Ein Ereignis mit ACTION_MOVE kann beispielsweise eine Bewegung für alle Zeiger nach unten anzeigen.

Zeiger im Blick behalten

Verwenden Sie den Index und die ID des Zeigers, um die einzelnen Zeigerpositionen innerhalb eines MotionEvent zu verfolgen.

  • Index: Ein MotionEvent speichert Zeigerinformationen in einem Array. Der Index eines Zeigers ist seine Position innerhalb dieses Arrays. Die meisten MotionEvent-Methoden verwenden den Zeigerindex als Parameter und nicht als Zeiger-ID.
  • ID: Jeder Zeiger verfügt außerdem über eine ID-Zuordnung, die über Touchereignisse hinweg dauerhaft bleibt, um die Verfolgung eines einzelnen Zeigers über die gesamte Geste zu ermöglichen.

Einzelne Zeiger werden innerhalb eines Bewegungsereignisses in einer nicht definierten Reihenfolge angezeigt. Daher kann sich der Index eines Zeigers von einem Ereignis zum nächsten ändern. Die Zeiger-ID eines Zeigers bleibt jedoch garantiert konstant, solange der Zeiger aktiv bleibt. Verwenden Sie die Methode getPointerId(), um die ID eines Zeigers abzurufen und ihn über alle nachfolgenden Bewegungsereignisse 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);
    ...
}

Zur Unterstützung mehrerer Touchpointer können Sie alle aktiven Cursor mit ihren IDs zu ihrem jeweiligen ACTION_POINTER_DOWN- und ACTION_DOWN-Ereigniszeitpunkt im Cache speichern. Entfernen Sie die Zeiger an den zugehörigen ACTION_POINTER_UP- und ACTION_UP-Ereignissen aus dem Cache. Diese im Cache gespeicherten IDs können hilfreich sein, um andere Aktionsereignisse 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 festzustellen, welche Zeiger verschoben wurden.

Verwenden Sie die Funktion getActionIndex() nur mit den Ereignissen ACTION_POINTER_UP und ACTION_POINTER_DOWN. Verwenden Sie diese Funktion nicht mit ACTION_MOVE-Ereignissen, da sie immer 0 zurückgibt.

MotionEvent Aktionen abrufen

Verwenden Sie die Methode getActionMasked() oder die Kompatibilitätsversion MotionEventCompat.getActionMasked(), um die Aktion eines MotionEvent abzurufen. Im Gegensatz zur vorherigen getAction()-Methode ist getActionMasked() für mehrere Zeiger konzipiert. Sie gibt die Aktion ohne Zeigerindexe zurück. 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-Zeichnungsmuster.

Weitere Informationen

Weitere Informationen zu Eingabeereignissen finden Sie in den folgenden Referenzen: