Berührungs- und Zeigerbewegungen verfolgen

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

In dieser Lektion wird beschrieben, wie Sie Bewegungen bei Touch-Ereignissen erfassen.

Wenn sich die Position, der Druck oder die Größe des Kontakts ändert, wird mit einem ACTION_MOVE-Ereignis ein neues onTouchEvent() ausgelöst. Wie unter Gängige Gesten erkennen beschrieben, werden alle diese Ereignisse im Parameter MotionEvent von onTouchEvent() aufgezeichnet.

Da die fingerbasierte Berührung nicht immer die genaueste Form der Interaktion ist, basiert die Erkennung von Berührungsereignissen häufig mehr auf Bewegung als auf einem einfachen Kontakt. Damit Apps zwischen bewegungsbasierten Gesten (z. B. Wischen) und bewegungslosen Gesten (z. B. einmaligem Tippen) unterscheiden können, verwendet Android das Konzept Touch Slop. Der Touch Slop bezieht sich auf die Entfernung in Pixeln, die eine Berührung eines Nutzers zurücklegen kann, bevor die Geste als bewegungsbasierte Geste interpretiert wird. Weitere Informationen zu diesem Thema finden Sie unter Touch-Events in einer ViewGroup verwalten.

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

  • Die Start- und Endposition eines Zeigers, z. B. das Verschieben eines Bildschirmobjekts von Punkt A nach Punkt B.
  • Die Richtung, in die sich der Zeiger bewegt. Sie wird durch die X- und Y-Koordinaten bestimmt.
  • Verlauf. Sie können die Größe des Verlaufs einer Geste abrufen, indem Sie die MotionEvent-Methode getHistorySize() aufrufen. Mithilfe der getHistorical<Value>-Methoden des Bewegungsereignisses können Sie dann die Positionen, Größen, Zeit und Druck der einzelnen historischen Ereignisse abrufen. Der Verlauf ist nützlich, wenn Sie eine Spur des Fingers des Nutzers rendern, z. B. beim Zeichnen durch Berührung. Weitere Informationen findest du in der MotionEvent-Referenz.
  • Die Geschwindigkeit des Zeigers bei der Bewegung über den Touchscreen.

Weitere Informationen finden Sie in den folgenden verwandten Ressourcen:

Trackgeschwindigkeit

Sie können eine bewegungsbasierte Touch-Geste festlegen, die auf der Entfernung oder Richtung basiert, die der Zeiger zurücklegt. Die Geschwindigkeit ist jedoch oft ein ausschlaggebender Faktor, um die Eigenschaften einer Geste zu erfassen oder zu entscheiden, ob die Geste ausgeführt wurde. Android bietet die VelocityTracker-Klasse, um die Berechnung der Geschwindigkeit zu vereinfachen. Mit VelocityTracker können Sie die Geschwindigkeit von Berührungsereignissen erfassen. Dies ist nützlich für Gesten, bei denen die Geschwindigkeit Teil des Kriteriums für die Geste ist, z. B. ein Fling.

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

Zeigeraufnahme verwenden

Einige Anwendungen, z. B. Spiele sowie Remote Desktop- und Virtualisierungsclients, profitieren davon, die Kontrolle über den Mauszeiger zu erhalten. Die Zeigeraufnahme ist eine Funktion ab Android 8.0 (API-Level 26). Sie ermöglicht diese Steuerung, indem alle Mausereignisse an eine fokussierte Ansicht in deiner App gesendet werden.

Zeigererfassung anfordern

Eine Ansicht in Ihrer Anwendung kann nur dann die Zeigeraufnahme anfordern, wenn die Ansichtshierarchie, in der sie enthalten ist, den Fokus hat. Aus diesem Grund sollte die Erfassung per Anfragezeiger bei bestimmten Nutzeraktionen in der Ansicht erfolgen, z. B. während eines onClick()-Ereignisses oder im Event-Handler onWindowFocusChanged() Ihrer Aktivität.

Rufen Sie die Methode requestPointerCapture() für die Ansicht auf, um die Zeigererfassung anzufordern. Das folgende Codebeispiel zeigt, wie die Zeigererfassung angefordert wird, wenn der Nutzer auf eine Ansicht klickt:

Kotlin

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

Java

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

Sobald die Anfrage zum Erfassen des Zeigers erfolgreich war, ruft Android onPointerCaptureChange(true) auf. Das System liefert die Mausereignisse an die fokussierte Ansicht in Ihrer App, solange sie sich in derselben Ansichtshierarchie befindet wie die Ansicht, die die Erfassung angefordert hat. Andere Apps empfangen erst wieder Mausereignisse, wenn die Erfassung veröffentlicht wird, einschließlich ACTION_OUTSIDE-Ereignissen. Android liefert Zeigerereignisse von anderen Quellen als der Maus wie gewohnt aus, aber der Mauszeiger ist nicht mehr sichtbar.

Erfasste Zeigerereignisse verarbeiten

Sobald eine Ansicht die Zeigeraufnahme erfolgreich erfasst hat, liefert Android die Mausereignisse. Die fokussierte Ansicht kann die Ereignisse verarbeiten, indem sie eine der folgenden Aufgaben ausführt:

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, empfängt die Ansicht ein MotionEvent mit Zeigerkoordinaten, die relative Bewegungen wie X- oder Y-Deltas angeben, ähnlich den Koordinaten, die von einem Trackballgerät bereitgestellt werden. Sie können die Koordinaten mit getX() und getY() abrufen.

Zeigeraufnahme loslassen

Die Ansicht in Ihrer App kann die Zeigererfassung freigeben, indem releasePointerCapture() aufgerufen wird, 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 Aufnahme aus der Ansicht entfernen, ohne explizit releasePointerCapture() aufzurufen. Dies liegt normalerweise daran, dass die Ansichtshierarchie mit der Ansicht, die die Erfassung angefordert hat, den Fokus verliert.