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 gravados no parâmetro
MotionEvent
de
onTouchEvent()
.
Como o toque com o 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 de movimento (como deslizar) e sem movimento (como um único toque), o Android inclui a noção de tolerância de toque. A tolerância de toque se refere à distância em pixels que o toque do usuário pode percorrer antes que o gesto seja interpretado como um gesto de 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 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 em que o ponteiro está viajando, conforme determinado pelas coordenadas X e Y.
- O histórico. Você pode encontrar o tamanho do histórico de um gesto chamando o
método
MotionEvent
getHistorySize()
. É possível saber as posições, tamanhos, horários e 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, por exemplo, para desenhos por toque. Consulte a referência doMotionEvent
para mais detalhes. - A velocidade do ponteiro conforme ele se move pela 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 costuma ser 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 do gesto, como
uma rolagem rápida.
Confira um exemplo que ilustra o objetivo 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, têm o controle do ponteiro do mouse. A captura de ponteiro é um recurso disponível no Android 8.0 (API de nível 26) 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 pode solicitar a captura de ponteiro somente quando a hierarquia de visualizações
que a contém estiver em foco. Por esse motivo, solicite a captura de ponteiro quando houver uma
ação específica do usuário na visualização, como 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 a seguir 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(); }
Quando a solicitação para capturar o ponteiro for bem-sucedida, o Android chamará
onPointerCaptureChange(true)
.
O sistema entrega os eventos do mouse à visualização em foco no app, desde que
ela esteja na mesma hierarquia da visualização que solicitou a captura. Outros
apps param de receber eventos de mouse até que a captura seja liberada, incluindo
os eventos
ACTION_OUTSIDE
. O Android envia eventos de ponteiro de outras origens além do mouse
normalmente, mas o ponteiro do mouse não fica mais visível.
Processar eventos de ponteiro capturados
Depois que uma visualização adquire a captura de ponteiro, o Android exibe os eventos do mouse. A visualização em foco pode processar os eventos realizando uma das seguintes tarefas:
- Se você está usando uma visualização personalizada, substitua
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; } });
Se você usa uma visualização personalizada ou registra 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. Recupere 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 neste exemplo de código:
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.