Esta lição descreve como rastrear o movimento em eventos de toque.
Um novo
onTouchEvent()
é acionado com um
evento ACTION_MOVE
sempre que a posição, pressão ou tamanho do contato de toque atual muda. Conforme
descrito em Detectar gestos comuns, todos
esses eventos são registrados no parâmetro
MotionEvent
de
onTouchEvent()
.
Como o toque do dedo nem sempre é a forma mais precisa de interação, a detecção de eventos de toque geralmente se baseia mais no movimento do que no simples contato. Para ajudar os apps a distinguir entre gestos baseados em movimento (como deslizar) e gestos sem movimento (como um único toque), o Android inclui a noção de tolerância de toque. A tolerância de toque refere-se à distância em pixels que o toque do usuário pode percorrer antes que o gesto seja interpretado como baseado em movimento. Para mais informações sobre esse tópico, consulte Gerenciar eventos de toque em um ViewGroup.
Há várias maneiras de rastrear o movimento em um gesto, dependendo das necessidades do seu aplicativo. Confira alguns exemplos:
- As posições inicial e final de um ponteiro, como mover um objeto na tela do ponto A para o ponto B.
- A direção do percurso do ponteiro, conforme determinado pelas coordenadas X e Y.
- O histórico. Para encontrar o tamanho do histórico de um gesto, chame o
método
MotionEvent
getHistorySize()
. É possível saber as posições, os tamanhos, o horário e as pressões de cada um dos eventos históricos usando os métodosgetHistorical<Value>
do evento de movimento. O histórico é útil ao renderizar um rastro do dedo do usuário, como para mostrar por toques. Consulte a referênciaMotionEvent
para mais detalhes. - A velocidade do ponteiro conforme ele se move na tela touchscreen.
Confira estes recursos relacionados:
- Visão geral dos eventos de entrada
- Visão geral dos sensores
- Tornar uma visualização personalizada interativa
Velocidade de rastreamento
Você pode ter um gesto de movimento baseado na distância ou direção
que o ponteiro percorre. No entanto, a velocidade geralmente é um fator determinante para rastrear
as características de um gesto ou decidir se ele ocorreu. Para facilitar o cálculo da velocidade, o Android oferece a classe VelocityTracker
.
VelocityTracker
ajuda a rastrear a velocidade dos eventos de toque. Isso é útil
para gestos em que a velocidade faz parte dos critérios, como
uma rolagem rápida.
Este é um exemplo que ilustra a finalidade dos métodos na
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; } }
Usar captura de ponteiro
Alguns apps, como jogos e clientes de área de trabalho remota e virtualização, se beneficiam do controle sobre o ponteiro do mouse. A captura de ponteiro é um recurso disponível no Android 8.0 (nível 26 da API) e versões mais recentes que oferece esse controle enviando todos os eventos do mouse para uma visualização focada no app.
Solicitar captura de ponteiro
Uma visualização no app só pode solicitar a captura de ponteiro quando a hierarquia de visualização
que a contém está em foco. Por esse motivo, solicite a captura de ponteiro quando houver uma
ação específica do usuário na visualização, por exemplo, durante um evento
onClick()
ou no
manipulador de eventos
onWindowFocusChanged()
da sua atividade.
Para solicitar a captura de ponteiro, chame o método
requestPointerCapture()
na visualização. O exemplo de código abaixo mostra como solicitar a captura
de ponteiro quando o usuário clica em uma visualização:
Kotlin
fun onClick(view: View) { view.requestPointerCapture() }
Java
@Override public void onClick(View view) { view.requestPointerCapture(); }
Depois que a solicitação para capturar o ponteiro for concluída, o Android chamará
onPointerCaptureChange(true)
.
O sistema envia os eventos de mouse para a visualização focada no seu app, desde que
ela esteja na mesma hierarquia da visualização que solicitou a captura. Outros
apps vão deixar de receber eventos de mouse até que a captura seja liberada, incluindo
eventos
ACTION_OUTSIDE
. O Android envia normalmente eventos de ponteiro de outras origens, mas o ponteiro do mouse não fica mais visível.
Processar eventos de ponteiro capturados
Depois que uma visualização recebe a captura de ponteiro, o Android envia os eventos do mouse. A visualização focada pode processar os eventos realizando uma das tarefas abaixo:
- Se você estiver usando uma visualização personalizada, modifique
onCapturedPointerEvent(MotionEvent)
. - Caso contrário, registre um
OnCapturedPointerListener
.
O exemplo de código abaixo mostra como implementar
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; }
O exemplo de código abaixo mostra como registrar um
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; } });
Independentemente de você usar uma visualização personalizada ou registrar um listener, sua visualização recebe um
MotionEvent
com coordenadas de ponteiro que especificam movimentos relativos, como deltas X
ou Y, semelhantes às coordenadas enviadas por um dispositivo trackball. É possível
extrair as coordenadas usando
getX()
e
getY()
.
Liberar captura de ponteiro
A visualização no seu app pode liberar a captura de ponteiro chamando
releasePointerCapture()
,
conforme mostrado no exemplo de código a seguir.
Kotlin
override fun onClick(view: View) { view.releasePointerCapture() }
Java
@Override public void onClick(View view) { view.releasePointerCapture(); }
O sistema pode retirar a captura da visualização sem que você chame releasePointerCapture()
explicitamente, geralmente porque a hierarquia de visualização
que contém a visualização que solicita a captura perde o foco.