Berührungs- und Zeigerbewegungen verfolgen

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

In dieser Lektion wird beschrieben, wie Bewegungen bei Berührungsereignissen erfasst werden.

Ein neues onTouchEvent() wird mit einem ACTION_MOVE-Ereignis ausgelöst, wenn sich die aktuelle Position, der Druck oder die Größe des Kontaktkontakts ändert. Wie unter Häufige Touch-Gesten erkennen beschrieben, werden alle diese Ereignisse im Parameter MotionEvent von onTouchEvent() aufgezeichnet.

Da fingerbasiertes Berühren nicht immer die genaueste Form der Interaktion ist, basiert die Erkennung von Berührungsereignissen oft mehr auf Bewegung als auf einem einfachen Kontakt. Damit Apps zwischen bewegungsbasierten Gesten (z. B. Wischen) und bewegungsfreien Gesten (z. B. einmaliges Tippen) unterscheiden können, umfasst Android das Konzept Touch Slop. Touch Slop bezieht sich auf den Abstand in Pixeln, den ein Nutzer bei einer Berührung bewegen kann, bevor die Geste als bewegungsbasierte Geste interpretiert wird. Weitere Informationen zu diesem Thema finden Sie unter Touch-Ereignisse in einer ViewGroup verwalten.

Je nach den Anforderungen Ihrer App gibt es mehrere Möglichkeiten, Bewegungen in einer Geste zu verfolgen. Beispiele:

  • Die Start- und Endposition eines Zeigers, z. B. das Verschieben eines Objekts auf dem Bildschirm von Punkt A zu Punkt B.
  • Die Richtung, in die sich der Zeiger bewegt, wie durch die X- und Y-Koordinaten bestimmt.
  • Verlauf. Die Größe des Verlaufs einer Touch-Geste können Sie über die Methode MotionEvent getHistorySize() abrufen. Anschließend können Sie mithilfe der getHistorical<Value>-Methoden des Bewegungsereignisses Position, Größe, Zeit und Druck der einzelnen historischen Ereignisse abrufen. Der Verlauf ist nützlich, wenn eine Spur des Fingers des Nutzers gerendert wird, z. B. beim Zeichnen per Berührung. Weitere Informationen finden Sie in der MotionEvent-Referenz.
  • Die Geschwindigkeit des Zeigers, wenn er sich über den Touchscreen bewegt.

Weitere Informationen finden Sie in den folgenden Ressourcen:

Geschwindigkeit verfolgen

Sie können eine bewegungsbasierte Geste einrichten, die auf der Entfernung oder Richtung basiert, die der Zeiger zurücklegt. Die Geschwindigkeit ist jedoch häufig ein ausschlaggebender Faktor für die Verfolgung der Eigenschaften einer Geste oder die Entscheidung, ob die Geste erfolgt ist. Android bietet die Klasse VelocityTracker, um die Berechnung der Geschwindigkeit zu vereinfachen. VelocityTracker hilft dir, die Geschwindigkeit von Berührungsereignissen zu verfolgen. Dies ist nützlich bei Gesten, bei denen die Geschwindigkeit Teil des Kriteriums für die Geste ist, z. B. ein Ziehen.

Das folgende Beispiel veranschaulicht den Zweck der Methoden in der VelocityTracker API:

Kotlin

private const val DEBUG_TAG = "Velocity"

class MainActivity : Activity() {
    private var mVelocityTracker: VelocityTracker? = null

    override fun onTouchEvent(event: MotionEvent): Boolean {

        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                // Reset the velocity tracker back to its initial state.
                mVelocityTracker?.clear()
                // If necessary, retrieve a new VelocityTracker object to watch
                // the velocity of a motion.
                mVelocityTracker = mVelocityTracker ?: VelocityTracker.obtain()
                // Add a user's movement to the tracker.
                mVelocityTracker?.addMovement(event)
            }
            MotionEvent.ACTION_MOVE -> {
                mVelocityTracker?.apply {
                    val pointerId: Int = event.getPointerId(event.actionIndex)
                    addMovement(event)
                    // When you want to determine the velocity, call
                    // computeCurrentVelocity(). Then, call getXVelocity() and
                    // getYVelocity() to retrieve the velocity for each pointer
                    // ID.
                    computeCurrentVelocity(1000)
                    // Log velocity of pixels per second. It's best practice to
                    // use VelocityTrackerCompat where possible.
                    Log.d("", "X velocity: ${getXVelocity(pointerId)}")
                    Log.d("", "Y velocity: ${getYVelocity(pointerId)}")
                }
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                // Return a VelocityTracker object back to be re-used by others.
                mVelocityTracker?.recycle()
                mVelocityTracker = null
            }
        }
        return true
    }
}

Java

public class MainActivity extends Activity {
    private static final String DEBUG_TAG = "Velocity";
        ...
    private VelocityTracker mVelocityTracker = null;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int index = event.getActionIndex();
        int action = event.getActionMasked();
        int pointerId = event.getPointerId(index);

        switch(action) {
            case MotionEvent.ACTION_DOWN:
                if(mVelocityTracker == null) {
                    // Retrieve a new VelocityTracker object to watch the
                    // velocity of a motion.
                    mVelocityTracker = VelocityTracker.obtain();
                }
                else {
                    // Reset the velocity tracker back to its initial state.
                    mVelocityTracker.clear();
                }
                // Add a user's movement to the tracker.
                mVelocityTracker.addMovement(event);
                break;
            case MotionEvent.ACTION_MOVE:
                mVelocityTracker.addMovement(event);
                // When you want to determine the velocity, call
                // computeCurrentVelocity(). Then call getXVelocity() and
                // getYVelocity() to retrieve the velocity for each pointer ID.
                mVelocityTracker.computeCurrentVelocity(1000);
                // Log velocity of pixels per second. It's best practice to use
                // VelocityTrackerCompat where possible.
                Log.d("", "X velocity: " + mVelocityTracker.getXVelocity(pointerId));
                Log.d("", "Y velocity: " + mVelocityTracker.getYVelocity(pointerId));
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                // Return a VelocityTracker object back to be re-used by others.
                mVelocityTracker.recycle();
                break;
        }
        return true;
    }
}

Pointer Capture verwenden

Einige Anwendungen wie Spiele, Remote-Desktop- und Virtualisierungsclients profitieren von der Kontrolle über den Mauszeiger. Die Zeigererfassung ist eine in Android 8.0 (API-Level 26) und höher verfügbare Funktion, die dieses Steuerelement bietet, indem alle Mausereignisse in einer fokussierten Ansicht in Ihrer App ausgeliefert werden.

Zeigererfassung anfordern

Eine Ansicht in Ihrer Anwendung kann nur dann die Zeigererfassung anfordern, wenn die Ansichtshierarchie, in der sie enthalten ist, im Fokus ist. Aus diesem Grund sollte die Anfragezeigererfassung erfolgen, wenn eine bestimmte Nutzeraktion in der Ansicht erfolgt, z. B. während eines onClick()-Ereignisses oder im onWindowFocusChanged()-Event-Handler Ihrer Aktivität.

Wenn Sie eine Zeigererfassung anfordern möchten, rufen Sie die Methode requestPointerCapture() für die Ansicht auf. Das folgende Codebeispiel zeigt, wie Sie die Zeigererfassung anfordern, wenn der Nutzer auf eine Ansicht klickt:

Kotlin

fun onClick(view: View) {
    view.requestPointerCapture()
}

Java

@Override
public void onClick(View view) {
    view.requestPointerCapture();
}

Wenn die Anfrage zum Erfassen des Zeigers erfolgreich ist, ruft Android onPointerCaptureChange(true) auf. Das System liefert die Mausereignisse an die fokussierte Ansicht in Ihrer App, solange sie sich in derselben Ansichtshierarchie wie die Ansicht befindet, die die Erfassung angefordert hat. Andere Apps empfangen keine Mausereignisse mehr, bis die Erfassung freigegeben wird, einschließlich ACTION_OUTSIDE-Ereignissen. Android liefert Zeigerereignisse von anderen Quellen als der Maus ganz normal, aber der Mauszeiger ist nicht mehr sichtbar.

Erfasste Zeigerereignisse verarbeiten

Sobald eine Ansicht die Zeigererfassung erfolgreich erfasst hat, löst Android die Mausereignisse aus. In der fokussierten Ansicht können Sie die Ereignisse verarbeiten, indem Sie eine der folgenden Aufgaben ausführen:

Das folgende Codebeispiel zeigt, wie onCapturedPointerEvent(MotionEvent) implementiert wird:

Kotlin

override fun onCapturedPointerEvent(motionEvent: MotionEvent): Boolean {
    // Get the coordinates required by your app.
    val verticalOffset: Float = motionEvent.y
    // Use the coordinates to update your view and return true if the event is
    // successfully processed.
    return true
}

Java

@Override
public boolean onCapturedPointerEvent(MotionEvent motionEvent) {
  // Get the coordinates required by your app.
  float verticalOffset = motionEvent.getY();
  // Use the coordinates to update your view and return true if the event is
  // successfully processed.
  return true;
}

Das folgende Codebeispiel zeigt, wie ein OnCapturedPointerListener registriert wird:

Kotlin

myView.setOnCapturedPointerListener { view, motionEvent ->
    // Get the coordinates required by your app.
    val horizontalOffset: Float = motionEvent.x
    // Use the coordinates to update your view and return true if the event is
    // successfully processed.
    true
}

Java

myView.setOnCapturedPointerListener(new View.OnCapturedPointerListener() {
  @Override
  public boolean onCapturedPointer (View view, MotionEvent motionEvent) {
    // Get the coordinates required by your app.
    float horizontalOffset = motionEvent.getX();
    // Use the coordinates to update your view and return true if the event is
    // successfully processed.
    return true;
  }
});

Unabhängig davon, ob Sie eine benutzerdefinierte Ansicht verwenden oder einen Listener registrieren, erhält die Ansicht eine MotionEvent mit Zeigerkoordinaten, die relative Bewegungen wie X- oder Y-Deltas angeben, ähnlich den Koordinaten, die von einem Trackball-Gerät geliefert werden. Sie können die Koordinaten mit getX() und getY() abrufen.

Aufnahme mit Releasezeiger

Die Ansicht in Ihrer App kann die Zeigererfassung freigeben, indem sie releasePointerCapture() aufruft, wie im folgenden Codebeispiel gezeigt:

Kotlin

override fun onClick(view: View) {
    view.releasePointerCapture()
}

Java

@Override
public void onClick(View view) {
    view.releasePointerCapture();
}

Das System kann die Erfassung aus der Ansicht wegnehmen, ohne dass Sie releasePointerCapture() explizit aufrufen. Dies liegt häufig daran, dass die Ansichtshierarchie mit der Ansicht, die die Anfragen erfassen, den Fokus verliert.