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
MotionEventmetodogetHistorySize(). Puoi quindi ottenere le posizioni, le dimensioni, l'ora e le pressioni di ciascuno degli eventi storici utilizzando i metodigetHistorical<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 riferimentoMotionEvent. - La velocità del puntatore mentre si sposta sul touchscreen.
Consulta le seguenti risorse correlate:
- Panoramica degli eventi di input
- Panoramica dei sensori
- Rendere interattiva una visualizzazione personalizzata
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à:
- Se utilizzi una visualizzazione personalizzata, esegui l'override di
onCapturedPointerEvent(MotionEvent). - In caso contrario, registra un
OnCapturedPointerListener.
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.