Um gesto com vários toques acontece quando diversos ponteiros (dedos) tocam na tela ao mesmo tempo. Este documento descreve como detectar gestos que envolvem vários ponteiros.
Rastrear vários ponteiros
Quando vários ponteiros tocam na tela ao mesmo tempo, o sistema gera os seguintes eventos de toque:
ACTION_DOWN: enviado quando o primeiro ponteiro toca na tela. Isso inicia o gesto. Os dados de ponteiro para esse ponteiro estão sempre no índice0doMotionEvent.ACTION_POINTER_DOWN: enviado quando ponteiros extras entram na tela depois do primeiro. É possível receber o índice do ponteiro que acabou de ser pressionado usandogetActionIndex().ACTION_MOVE: enviado quando ocorre uma mudança em um gesto, envolvendo qualquer número de ponteiros.ACTION_POINTER_UP: enviado quando um ponteiro não primário sobe. É possível conseguir o índice do ponteiro que acabou de subir usandogetActionIndex().ACTION_UP: enviado quando o último ponteiro deixa a tela.ACTION_CANCEL: indica que todo o gesto, incluindo todos os ponteiros, foi cancelado.
Gestos de início e término
Um gesto é uma série de eventos que começa com um evento ACTION_DOWN
e termina com um evento ACTION_UP ou
ACTION_CANCEL. Há um gesto ativo por vez. As ações
DOWN, MOVE, UP e CANCEL se aplicam ao gesto inteiro. Por exemplo, um
evento com ACTION_MOVE pode indicar um movimento para baixo de todos os ponteiros
naquele momento.
Acompanhar ponteiros
Use o índice e o ID do ponteiro para rastrear as posições dos ponteiros individuais em um MotionEvent.
- Índice: um
MotionEventarmazena informações de ponteiro em uma matriz. O índice de um ponteiro é a posição dele dentro dessa matriz. A maioria dos métodosMotionEventusa o índice de ponteiro como um parâmetro, não o ID dele. - ID: cada ponteiro também tem um mapeamento de ID que permanece persistente em eventos de toque para permitir o rastreamento de um ponteiro individual em todo o gesto.
Os ponteiros individuais aparecem em um evento de movimento em uma ordem indefinida. Assim, o índice de um ponteiro pode mudar de um evento para o próximo, mas o ID do ponteiro permanecerá constante enquanto ele estiver ativo. Use o método
getPointerId()
para ver o ID de um ponteiro e rastreá-lo em todos os eventos de movimento subsequentes
em um gesto. Em seguida, para eventos de movimento sucessivos, use o método
findPointerIndex()
para obter o índice de ponteiro de um determinado código nesse evento de movimento.
Exemplo:
Kotlin
private var mActivePointerId: Int = 0 override fun onTouchEvent(event: MotionEvent): Boolean { ... // Get the pointer ID. mActivePointerId = event.getPointerId(0) // ... Many touch events later... // Use the pointer ID to find the index of the active pointer // and fetch its position. val (x: Float, y: Float) = event.findPointerIndex(mActivePointerId).let { pointerIndex -> // Get the pointer's current position. event.getX(pointerIndex) to event.getY(pointerIndex) } ... }
Java
private int mActivePointerId; public boolean onTouchEvent(MotionEvent event) { ... // Get the pointer ID. mActivePointerId = event.getPointerId(0); // ... Many touch events later... // Use the pointer ID to find the index of the active pointer // and fetch its position. int pointerIndex = event.findPointerIndex(mActivePointerId); // Get the pointer's current position. float x = event.getX(pointerIndex); float y = event.getY(pointerIndex); ... }
Para oferecer suporte a vários ponteiros de toque, é possível armazenar em cache todos os ponteiros ativos com
os IDs deles no tempo de evento ACTION_POINTER_DOWN e
ACTION_DOWN individual. Remova os ponteiros do cache nos eventos ACTION_POINTER_UP e ACTION_UP. Esses IDs armazenados em cache podem ser úteis para processar outros eventos de ação corretamente. Por exemplo, ao processar um evento ACTION_MOVE, encontre o índice de cada ID de ponteiro ativo em cache, recupere as coordenadas do ponteiro usando as funções getX() e getY() e compare essas coordenadas com as coordenadas em cache para descobrir quais ponteiros foram movidos.
Use a função getActionIndex() apenas com eventos ACTION_POINTER_UP e ACTION_POINTER_DOWN. Não use essa função com eventos ACTION_MOVE, porque ela sempre retorna 0.
Recuperar ações do MotionEvent
Use o método
getActionMasked()
ou a versão de compatibilidade
MotionEventCompat.getActionMasked()
para recuperar a ação de um MotionEvent. Ao contrário do método getAction() anterior, o getActionMasked() foi desenvolvido para funcionar com vários ponteiros. Ele retorna a ação sem os índices de ponteiro. Para ações com um
índice de ponteiro válido, use getActionIndex() para retornar o índice dos
ponteiros associados à ação, conforme mostrado no snippet a seguir:
Kotlin
val (xPos: Int, yPos: Int) = MotionEventCompat.getActionMasked(event).let { action -> Log.d(DEBUG_TAG, "The action is ${actionToString(action)}") // Get the index of the pointer associated with the action. MotionEventCompat.getActionIndex(event).let { index -> // The coordinates of the current screen contact, relative to // the responding View or Activity. MotionEventCompat.getX(event, index).toInt() to MotionEventCompat.getY(event, index).toInt() } } if (event.pointerCount > 1) { Log.d(DEBUG_TAG, "Multitouch event") } else { // Single touch event. Log.d(DEBUG_TAG, "Single touch event") } ... // Given an action int, returns a string description. fun actionToString(action: Int): String { return when (action) { MotionEvent.ACTION_DOWN -> "Down" MotionEvent.ACTION_MOVE -> "Move" MotionEvent.ACTION_POINTER_DOWN -> "Pointer Down" MotionEvent.ACTION_UP -> "Up" MotionEvent.ACTION_POINTER_UP -> "Pointer Up" MotionEvent.ACTION_OUTSIDE -> "Outside" MotionEvent.ACTION_CANCEL -> "Cancel" else -> "" } }
Java
int action = MotionEventCompat.getActionMasked(event); // Get the index of the pointer associated with the action. int index = MotionEventCompat.getActionIndex(event); int xPos = -1; int yPos = -1; Log.d(DEBUG_TAG,"The action is " + actionToString(action)); if (event.getPointerCount() > 1) { Log.d(DEBUG_TAG,"Multitouch event"); // The coordinates of the current screen contact, relative to // the responding View or Activity. xPos = (int)MotionEventCompat.getX(event, index); yPos = (int)MotionEventCompat.getY(event, index); } else { // Single touch event. Log.d(DEBUG_TAG,"Single touch event"); xPos = (int)MotionEventCompat.getX(event, index); yPos = (int)MotionEventCompat.getY(event, index); } ... // Given an action int, returns a string description public static String actionToString(int action) { switch (action) { case MotionEvent.ACTION_DOWN: return "Down"; case MotionEvent.ACTION_MOVE: return "Move"; case MotionEvent.ACTION_POINTER_DOWN: return "Pointer Down"; case MotionEvent.ACTION_UP: return "Up"; case MotionEvent.ACTION_POINTER_UP: return "Pointer Up"; case MotionEvent.ACTION_OUTSIDE: return "Outside"; case MotionEvent.ACTION_CANCEL: return "Cancel"; } return ""; }
Outros recursos
Para mais informações relacionadas a eventos de entrada, consulte as seguintes referências:
- Visão geral dos eventos de entrada
- Visão geral dos sensores
- Tornar uma visualização personalizada interativa
- Arrastar e dimensionar