Monitora i movimenti del tocco e del puntatore

Prova la modalità Scrivi
Jetpack Compose è il toolkit dell'interfaccia utente consigliato per Android. Scopri come usare tocco e input in Scrivi.

Questa lezione descrive come tenere traccia dei movimenti negli eventi di tocco.

Un nuovo elemento onTouchEvent() viene attivato con un evento ACTION_MOVE ogni volta che la posizione attuale del contatto di contatto, la pressione o le dimensioni cambiano. Come descritto in Rileva gesti comuni, tutti questi eventi vengono registrati nel parametro MotionEvent di onTouchEvent().

Poiché il tocco basato sulle dita non è sempre la forma di interazione più precisa, il rilevamento degli eventi tocco si basa spesso più sul movimento che sul semplice contatto. Per aiutare le app a distinguere tra gesti basati sul movimento (ad esempio uno scorrimento) e non mobili (ad esempio un singolo tocco), Android include la nozione di inclinazione del tocco. La inclinazione al tocco si riferisce alla distanza in pixel che il tocco dell'utente può vagare prima che il gesto venga interpretato come un gesto basato sul movimento. Per ulteriori informazioni su questo argomento, consulta Gestire gli eventi tocco in un ViewGroup.

Esistono diversi modi per tenere traccia dei movimenti in un gesto, a seconda delle esigenze della tua applicazione. Ecco alcuni esempi:

  • La posizione iniziale e finale di un puntatore, ad esempio lo spostamento di un oggetto sullo schermo dal punto A al punto B.
  • La direzione in cui si muove il puntatore, come determinata dalle coordinate X e Y.
  • Cronologia. Puoi trovare la dimensione della cronologia di un gesto chiamando il metodo MotionEvent getHistorySize(). Puoi quindi ottenere posizioni, dimensioni, tempo e pressioni di ciascuno degli eventi storici usando i metodi getHistorical<Value> degli eventi di movimento. La cronologia è utile per il rendering di una traccia del dito dell'utente, ad esempio per il tocco. Per informazioni dettagliate, consulta il riferimento MotionEvent.
  • La velocità del puntatore mentre si sposta sul touchscreen.

Fai riferimento alle seguenti risorse correlate:

Velocità del rilevamento

Puoi avere un gesto basato sul movimento basato sulla distanza o sulla direzione di spostamento del puntatore. Tuttavia, la velocità è spesso un fattore determinante nel tenere traccia delle caratteristiche di un gesto o nel decidere se si è verificato il gesto. Per semplificare il calcolo della velocità, Android fornisce la classe VelocityTracker. VelocityTracker ti aiuta a monitorare la velocità degli eventi tocco. È utile per i gesti in cui la velocità fa parte dei criteri per il gesto, ad esempio uno sfioramento.

Ecco un esempio che illustra lo scopo dei metodi nell'API VelocityTracker:

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

Usa acquisizione con puntatore

Alcune app, come giochi e client di desktop remoto e di virtualizzazione, traggono vantaggio dall'avere il controllo sul puntatore del mouse. L'acquisizione del puntatore è una funzionalità disponibile in Android 8.0 (livello API 26) e versioni successive che offre questo controllo pubblicando tutti gli eventi del mouse in una visualizzazione specifica nella tua app.

Richiedi acquisizione del puntatore

Una vista nella tua app può richiedere l'acquisizione del puntatore solo quando la gerarchia delle visualizzazioni che la contiene è attiva. Per questo motivo, richiedi l'acquisizione del puntatore quando c'è un'azione utente specifica nella vista, ad esempio durante un evento onClick() o nel gestore eventi onWindowFocusChanged() della tua attività.

Per richiedere l'acquisizione del puntatore, chiama il metodo requestPointerCapture() nella vista. Il seguente esempio di codice mostra come richiedere l'acquisizione con puntatore quando l'utente fa clic su una vista:

Kotlin

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

Java

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

Quando la richiesta per acquisire il puntatore ha esito positivo, Android chiama onPointerCaptureChange(true). Il sistema invia gli eventi del mouse alla visualizzazione con stato attivo della tua app purché si trovi nella stessa gerarchia di visualizzazione della vista che ha richiesto l'acquisizione. Altre app non ricevono più eventi del mouse fino al rilascio dell'acquisizione, inclusi gli eventi ACTION_OUTSIDE. Android fornisce eventi di puntatore da origini diverse dal mouse, come di consueto, ma il puntatore del mouse non è più visibile.

Gestire gli eventi di puntatore acquisiti

Una volta che una visualizzazione acquisisce correttamente l'acquisizione del puntatore, Android invia gli eventi del mouse. La visualizzazione con stato attivo può gestire gli eventi eseguendo una delle seguenti attività:

Il seguente esempio di codice mostra come implementare onCapturedPointerEvent(MotionEvent):

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

Il seguente esempio di codice mostra come registrare un OnCapturedPointerListener:

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

A prescindere dal fatto che utilizzi una visualizzazione personalizzata o registri un listener, la visualizzazione riceve un elemento MotionEvent con coordinate del puntatore che specificano movimenti relativi, ad esempio delta X o Y, simili alle coordinate fornite da un dispositivo trackball. Puoi recuperare le coordinate utilizzando getX() e getY().

Rilascia acquisizione del puntatore

La visualizzazione nella tua app può rilasciare l'acquisizione del puntatore chiamando releasePointerCapture(), come mostrato nell'esempio di codice che segue:

Kotlin

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

Java

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

Il sistema può rimuovere l'acquisizione dalla visualizzazione senza che tu debba chiamare esplicitamente releasePointerCapture(), in genere perché la gerarchia delle visualizzazioni contenente la visualizzazione su cui viene eseguita l'acquisizione delle richieste perde lo stato attivo.