Monitora i movimenti del tocco e del puntatore

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

Questa lezione descrive come monitorare il movimento negli eventi di tocco.

Un nuovo onTouchEvent() viene attivato con un evento ACTION_MOVE ogni volta che la posizione, la pressione o le dimensioni del contatto di tocco corrente cambiano. Come descritto in Rilevare i gesti comuni, tutti questi eventi vengono registrati nel MotionEvent parametro 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 sul semplice contatto. Per aiutare le app a distinguere tra i gesti basati sul movimento (ad esempio uno scorrimento) e i gesti non basati sul movimento (ad esempio un singolo tocco), Android include la nozione di touch slop. Il touch slop si riferisce alla distanza in pixel che il tocco di un utente può percorrere prima che il gesto venga interpretato come un gesto basato sul movimento. Per ulteriori informazioni su questo argomento, consulta Gestire gli eventi di tocco in un ViewGroup.

Esistono diversi modi per monitorare il movimento in un gesto, a seconda delle esigenze dell'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 sposta il puntatore, determinata dalle coordinate X e Y.
  • Cronologia. Puoi trovare le dimensioni della cronologia di un gesto chiamando il MotionEvent metodo getHistorySize(). Puoi quindi ottenere le posizioni, le dimensioni, l'ora e le pressioni di ciascuno degli eventi storici utilizzando i metodi getHistorical<Value> dell'evento di movimento. La cronologia è utile quando si esegue il rendering di una traccia del dito dell'utente, ad esempio per il disegno a tocco. Per i dettagli, consulta il riferimento MotionEvent.
  • La velocità del puntatore mentre si sposta sul touchscreen.

Consulta le seguenti risorse correlate:

Monitorare la velocità

Puoi avere un gesto basato sul movimento che si basa sulla distanza o sulla direzione in cui si sposta il puntatore. Tuttavia, la velocità è spesso un fattore determinante per monitorare le caratteristiche di un gesto o decidere se il gesto si è verificato. Per semplificare il calcolo della velocità, Android fornisce la VelocityTracker classe. VelocityTracker ti aiuta a monitorare la velocità degli eventi di tocco. Questa funzionalità è utile per i gesti in cui la velocità fa parte dei criteri del gesto, ad esempio uno scorrimento rapido.

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

Utilizzare l'acquisizione del puntatore

Alcune app, come i giochi e i client di desktop remoto e 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 inviando tutti gli eventi del mouse a una visualizzazione con stato attivo nella tua app.

Richiedere l'acquisizione del puntatore

Una visualizzazione nella tua app può richiedere l'acquisizione del puntatore solo quando la gerarchia di oggetti View che la contiene ha lo stato attivo. Per questo motivo, richiedi l'acquisizione del puntatore quando è presente un' azione utente specifica sulla visualizzazione, ad esempio durante un onClick() evento o nel onWindowFocusChanged() gestore di eventi della tua attività.

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

Kotlin

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

Java

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

Una volta che la richiesta di acquisizione del puntatore è andata a buon fine, Android chiama onPointerCaptureChange(true). Il sistema invia gli eventi del mouse alla visualizzazione con stato attivo nella tua app finché si trova nella stessa gerarchia di oggetti View della visualizzazione che ha richiesto l'acquisizione. Le altre app smettono di ricevere eventi del mouse finché l'acquisizione non viene rilasciata, inclusi gli ACTION_OUTSIDE eventi. Android invia gli eventi del puntatore da origini diverse dal mouse come di consueto, ma il puntatore del mouse non è più visibile.

Gestire gli eventi del 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à:

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

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

Rilasciare l'acquisizione del puntatore

La visualizzazione nella tua app può rilasciare l'acquisizione del puntatore chiamando 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 visualizzazione senza che tu chiami esplicitamente releasePointerCapture(), in genere perché la gerarchia di oggetti View contenente la visualizzazione che richiede l'acquisizione perde lo stato attivo.