Multi-Touch-Bewegungen

Schreiben Sie jetzt
Jetpack Compose ist das empfohlene UI-Toolkit für Android. Weitere Informationen zur Verwendung von Berührungen und Eingaben in „Schreiben“

Bei einer Multi-Touch-Geste tippen mehrere Zeiger (Finger) gleichzeitig auf den Bildschirm. In diesem Dokument wird beschrieben, wie Gesten mit mehreren Zeigern erkannt werden.

Mehrere Cursor verfolgen

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

  • ACTION_DOWN: wird gesendet, wenn der erste Zeiger auf den Bildschirm tippt. Dadurch wird die Geste gestartet. Die Zeigerdaten für diesen Zeiger befinden sich immer am Index 0 in MotionEvent.
  • ACTION_POINTER_DOWN: wird gesendet, wenn zusätzliche Zeiger nach dem ersten auf dem Bildschirm erscheinen. Mit getActionIndex() können Sie den Index des Zeigers abrufen, der gerade ausgefallen ist.
  • ACTION_MOVE: wird gesendet, wenn eine Änderung in einer Geste mit einer beliebigen Anzahl von Zeigern erfolgt.
  • ACTION_POINTER_UP: wird gesendet, wenn ein nicht primärer Zeiger nach oben bewegt wird. Sie können den Index des gerade gestiegenen Zeigers mit getActionIndex() abrufen.
  • ACTION_UP: wird gesendet, wenn der letzte Mauszeiger den Bildschirm verlässt.
  • ACTION_CANCEL: Gibt an, dass die gesamte Geste einschließlich aller Zeiger abgebrochen wurde.

Touch-Gesten zum Starten und Beenden

Eine Geste besteht aus einer Reihe von Ereignissen, die mit einem ACTION_DOWN-Ereignis beginnen und mit einem ACTION_UP- oder ACTION_CANCEL-Ereignis enden. Es ist immer nur eine Bewegung aktiv. 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 zu diesem Zeitpunkt anzeigen.

Zeiger im Blick behalten

Verwenden Sie den Index und die ID des Zeigers, um die einzelnen Zeigerpositionen innerhalb einer 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 anstelle der Zeiger-ID als Parameter.
  • ID: Jeder Zeiger hat auch eine ID-Zuordnung, die über Touch-Ereignisse hinweg dauerhaft bleibt, um einen einzelnen Zeiger über die gesamte Geste hinweg zu verfolgen.

Einzelne Zeiger erscheinen in einer nicht definierten Reihenfolge innerhalb eines Bewegungsereignisses. Somit kann sich der Index eines Zeigers von einem Ereignis zum nächsten ändern. Die Zeiger-ID eines Zeigers bleibt jedoch garantiert konstant, solange er aktiv ist. Mit der Methode getPointerId() rufen Sie die Zeiger-ID ab, um den Zeiger 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);
    ...
}

Damit mehrere Touchpointer unterstützt werden, kannst du alle aktiven Cursor mit ihren IDs zu ihren jeweiligen ACTION_POINTER_DOWN- und ACTION_DOWN-Ereignissen im Cache speichern. Entfernen Sie die Cursor bei den ACTION_POINTER_UP- und ACTION_UP-Ereignissen aus dem Cache. Diese im Cache gespeicherten IDs könnten für die Verarbeitung anderer Aktionsereignisse hilfreich sein. Wenn Sie beispielsweise ein ACTION_MOVE-Ereignis verarbeiten, müssen Sie den Index für jede im Cache gespeicherte aktive Zeiger-ID ermitteln, die Koordinaten des Zeigers mit den Funktionen getX() und getY() abrufen und diese Koordinaten dann mit den im Cache gespeicherten Koordinaten vergleichen, um festzustellen, welche Zeiger sich bewegt haben.

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 einer MotionEvent abzurufen. Im Gegensatz zur vorherigen Methode getAction() ist getActionMasked() so konzipiert, dass es mit mehreren Verweisen funktioniert. Sie gibt die Aktion ohne die Zeigerindizes 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-Zeichenmuster

Zusätzliche Ressourcen

Weitere Informationen zu Eingabeereignissen finden Sie in den folgenden Referenzen: