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, a pressão ou o tamanho do contato de toque atual muda. Conforme
descrito em Detectar gestos comuns, todos
esses eventos são registrados no
MotionEvent parâmetro de
onTouchEvent().
Como o toque com os dedos 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 contato simples. Para ajudar os apps a diferenciar gestos de movimento (como deslizar) de 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 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. Veja alguns exemplos:
- A posição 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.
- Histórico. É possível encontrar o tamanho do histórico de um gesto chamando o
MotionEventmétodogetHistorySize(). Em seguida, é possível acessar as posições, tamanhos, tempo 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, como para desenho por toque. Consulte a referênciaMotionEventpara mais detalhes. - A velocidade do ponteiro conforme ele se move na tela sensível ao toque.
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 na direção que o ponteiro percorre. No entanto, a velocidade geralmente é um fator determinante no rastreamento das características de um gesto ou na decisão de se o gesto ocorreu. Para facilitar o
cálculo da velocidade, o Android oferece a
VelocityTracker classe.
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 um deslizar rapidamente.
Confira 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 do ponteiro do mouse. A captura de ponteiro é um recurso disponível no Android 8.0 (nível 26 da API) e mais recente que proporciona esse controle enviando todos os eventos de mouse para uma visualização focalizada no seu app.
Solicitar captura de ponteiro
Uma visualização no seu app só pode solicitar a captura de ponteiro quando a hierarquia de visualização que a contém está em foco. Por isso, solicite a captura de ponteiro quando houver uma
ação específica do usuário na visualização, como durante um
onClick()
evento ou no
onWindowFocusChanged()
manipulador de eventos da sua atividade.
Para solicitar a captura de ponteiro, chame o
requestPointerCapture()
método 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 realizada, o Android chamará
onPointerCaptureChange(true).
O sistema enviará os eventos de mouse para a visualização focalizada no seu app, desde que ela esteja na mesma hierarquia de visualização da visualização que solicitou a captura. Outros
apps param de receber eventos de mouse até que a captura seja liberada, incluindo
ACTION_OUTSIDE
eventos. O Android envia eventos de ponteiro de outras fontes 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 recebe a captura do ponteiro, o Android envia os eventos de mouse. A visualização focalizada pode processar os eventos realizando uma das seguintes tarefas:
- Se você está usando uma visualização personalizada, modifique
onCapturedPointerEvent(MotionEvent). - Caso contrário, registre um
OnCapturedPointerListener.
O exemplo de código a seguir 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 a seguir 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
recuperar as coordenadas usando
getX() e
getY().
Liberar captura de ponteiro
A visualização no seu app pode liberar a captura do 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() de maneira explícita. Normalmente, isso acontece porque a hierarquia de visualização que contém a visualização que solicitou a captura perde o foco.