Um gesto com vários toques acontece quando diversos ponteiros (dedos) tocam na tela ao mesmo tempo. Esta lição descreve como detectar gestos que envolvem vários ponteiros.
Confira os seguintes recursos relacionados:
Rastrear vários ponteiros
Quando vários ponteiros tocam na tela ao mesmo tempo, o sistema gera os seguintes eventos de toque:
ACTION_DOWN
: para o primeiro ponteiro que toca a tela. Isso inicia o gesto. Os dados de ponteiro para esse ponteiro estão sempre no índice 0 doMotionEvent
.ACTION_POINTER_DOWN
: para ponteiros extras que entram na tela além do primeiro. Os dados desse ponteiro estão no índice retornado porgetActionIndex()
.ACTION_MOVE
: uma mudança ocorreu durante um gesto de pressionar.ACTION_POINTER_UP
: enviado quando um ponteiro não primário sobe.ACTION_UP
: enviado quando o último ponteiro deixa a tela.
Rastreie os ponteiros individuais em um MotionEvent
por meio do índice e do código de cada ponteiro:
- Índice: um
MotionEvent
armazena com eficiência informações sobre cada ponteiro em uma matriz. O índice de um ponteiro é a posição dele dentro dessa matriz. A maioria dos métodosMotionEvent
que você usa para interagir com ponteiros usa o índice do ponteiro como um parâmetro, não o código dele. - Código: cada ponteiro também tem um mapeamento de código que permanece nos eventos de toque para rastrear um ponteiro individual em todo o gesto.
A ordem em que os ponteiros individuais aparecem em um evento de movimento é indefinida. Assim, o índice de um ponteiro pode mudar de um evento para o próximo, mas o código do ponteiro permanecerá constante enquanto o ponteiro permanecer ativo. Use o método getPointerId()
para ver o código 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 ver o índice do 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); ... }
Conseguir a ação de um MotionEvent
Use sempre o método getActionMasked()
(ou melhor, a versão de compatibilidade MotionEventCompat.getActionMasked()
) para recuperar a ação de um MotionEvent
. Diferente do método getAction()
mais antigo, o getActionMasked()
foi desenvolvido para funcionar com vários ponteiros. Ele retorna a ação mascarada em andamento, sem incluir os bits do índice do ponteiro. Você pode usar getActionIndex()
para retornar o índice do ponteiro associado à ação. Isso é ilustrado no snippet abaixo.
Observação: este exemplo usa a classe MotionEventCompat
. Essa classe está na Biblioteca de Suporte. Use MotionEventCompat
para oferecer a melhor compatibilidade para uma ampla variedade de plataformas. Observe que o MotionEventCompat
não substitui a classe MotionEvent
. Em vez disso, ele oferece métodos utilitários estáticos para os quais você passa o objeto MotionEvent
a fim de receber a ação visada associada a esse evento.
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 ""; }
Para mais discussões sobre o uso de vários toques e para ver alguns exemplos, consulte a lição Arrastar e dimensionar.