Monitora i movimenti del tocco e del puntatore

Prova il metodo Scrivi
Jetpack Compose è il toolkit consigliato per la UI per Android. Scopri come utilizzare il tocco e l'input in Compose.

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

Un nuovo onTouchEvent() viene attivato con un evento ACTION_MOVE ogni volta che la posizione attuale del contatto del 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 di tocco si basa spesso più sul movimento che su un semplice contatto. Per aiutare le app a distinguere tra gesti basati sul movimento (ad esempio lo scorrimento) e gesti non di movimento (ad esempio un singolo tocco), Android include la nozione di inclinazione al tocco. Slop al tocco indica la distanza in pixel che l'utente può muovere con il tocco prima che il gesto venga interpretato come gesto basato sul movimento. Per ulteriori informazioni su questo argomento, vedi Gestire gli eventi touch in un ViewGroup.

Esistono diversi modi per rilevare il movimento in un gesto, a seconda delle esigenze dell'applicazione. Ecco alcuni esempi:

  • La posizione iniziale e finale di un puntatore, ad esempio spostare un oggetto sullo schermo da un punto A a un punto B.
  • La direzione in cui si sposta il puntatore, come determinato dalle coordinate X e Y.
  • Cronologia. Puoi conoscere le dimensioni della cronologia di un gesto chiamando il metodo MotionEvent getHistorySize(). Puoi quindi ottenere posizioni, dimensioni, tempo e pressione di ciascuno degli eventi storici utilizzando i metodi getHistorical<Value> dell'evento di movimento. La cronologia è utile quando si esegue il rendering di una scia del dito dell'utente, ad esempio per il disegno tattile. Per informazioni dettagliate, consulta il riferimento di MotionEvent.
  • La velocità del puntatore mentre si sposta sul touchscreen.

Consulta le seguenti risorse correlate:

Monitora la velocità

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 monitorare le caratteristiche di un gesto o nel decidere se il gesto si è verificato. Per semplificare il calcolo della velocità, Android fornisce la classe VelocityTracker. VelocityTracker ti aiuta a monitorare la velocità degli eventi touch. Ciò è utile per i gesti in cui la velocità fa parte dei criteri del gesto, ad esempio l'inversione.

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 puntatore

Alcune app, come i giochi, i client di desktop remoto e di virtualizzazione, traggono vantaggio dal controllo del puntatore del mouse. L'acquisizione del puntatore è una funzionalità disponibile in Android 8.0 (livello API 26) e versioni successive che fornisce questo controllo pubblicando tutti gli eventi del mouse in una vista mirata all'interno dell'app.

Richiedi acquisizione puntatore

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

Per richiedere l'acquisizione del puntatore, chiama il metodo requestPointerCapture() nella vista. L'esempio di codice riportato di seguito mostra come richiedere l'acquisizione del 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 di acquisizione del puntatore ha esito positivo, Android chiama onPointerCaptureChange(true). Il sistema invia gli eventi del mouse alla vista con lo stato attivo dell'app, purché si trovi nella stessa gerarchia di quella che ha richiesto l'acquisizione. Altre app non ricevono gli eventi del mouse fino al rilascio dell'acquisizione, inclusi gli eventi ACTION_OUTSIDE. Android invia gli eventi del puntatore da origini diverse dal mouse come normalmente, ma il puntatore del mouse non è più visibile.

Gestire gli eventi del puntatore acquisiti

Dopo che una vista acquisisce correttamente l'acquisizione del puntatore, Android genera gli eventi del mouse. La vista selezionata può gestire gli eventi eseguendo una delle seguenti attività:

L'esempio di codice seguente 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;
}

L'esempio di codice seguente mostra come registrare una 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;
  }
});

Sia che utilizzi una visualizzazione personalizzata o registri un listener, la vista riceve un MotionEvent con coordinate del puntatore che specificano movimenti relativi, come i delta X o Y, simili alle coordinate fornite da un dispositivo trackball. Puoi recuperare le coordinate utilizzando getX() e getY().

Acquisizione puntatore di rilascio

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

Kotlin

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

Java

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

Il sistema può rimuovere l'acquisizione dalla vista senza che tu debba chiamare esplicitamente releasePointerCapture(), in genere perché la gerarchia di visualizzazione contenente la vista che le richieste di acquisizione perde lo stato attivo.