Мультитач-жест — это одновременное касание экрана несколькими указателями (пальцами). В этом документе описывается, как обнаружить жесты, включающие несколько указателей.
Отслеживание нескольких указателей
Когда несколько указателей одновременно касаются экрана, система генерирует следующие события касания:
-
ACTION_DOWN
: отправляется, когда первый указатель касается экрана. Это начинает жест. Данные указателя для этого указателя всегда имеют индекс0
вMotionEvent
. -
ACTION_POINTER_DOWN
: отправляется, когда дополнительные указатели появляются на экране после первого. Вы можете получить индекс указателя, который только что упал, используяgetActionIndex()
. -
ACTION_MOVE
: отправляется, когда в жесте происходит изменение, включающее любое количество указателей. -
ACTION_POINTER_UP
: отправляется, когда неосновной указатель поднимается вверх. Вы можете получить индекс указателя, который только что поднялся, используяgetActionIndex()
. -
ACTION_UP
: отправляется, когда последний указатель покидает экран. -
ACTION_CANCEL
: указывает, что весь жест, включая все указатели, отменен.
Начало и завершение жестов
Жест — это серия событий, начинающаяся с события ACTION_DOWN
и заканчивающаяся событием ACTION_UP
или ACTION_CANCEL
. Одновременно активен один жест. Действия ВНИЗ, ДВИЖЕНИЕ, ВВЕРХ и ОТМЕНА применяются ко всему жесту. Например, событие с ACTION_MOVE
может указывать на движение всех указателей вниз в этот момент.
Следите за указателями
Используйте индекс и идентификатор указателя, чтобы отслеживать позиции отдельных указателей в MotionEvent
.
- Индекс :
MotionEvent
хранит информацию указателя в массиве. Индекс указателя — это его позиция в этом массиве. Большинство методовMotionEvent
принимают в качестве параметра индекс указателя, а не идентификатор указателя. - ID : каждый указатель также имеет сопоставление идентификатора, которое остается постоянным при всех событиях касания, что позволяет отслеживать отдельный указатель на протяжении всего жеста.
Отдельные указатели появляются в событии движения в неопределенном порядке. Таким образом, индекс указателя может меняться от одного события к другому, но идентификатор указателя гарантированно останется постоянным, пока указатель остается активным. Используйте метод getPointerId()
, чтобы получить идентификатор указателя, чтобы отслеживать указатель по всем последующим событиям движения в жесте. Затем для последовательных событий движения используйте метод findPointerIndex()
чтобы получить индекс указателя для данного идентификатора указателя в этом событии движения. Например:
Котлин
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) } ... }
Ява
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); ... }
Для поддержки нескольких указателей касания вы можете кэшировать все активные указатели с их идентификаторами в отдельные моменты времени событий ACTION_POINTER_DOWN
и ACTION_DOWN
. Удалите указатели из кеша в их событиях ACTION_POINTER_UP
и ACTION_UP
. Эти кэшированные идентификаторы могут оказаться полезными для правильной обработки других событий действий. Например, при обработке события ACTION_MOVE
найдите индекс для каждого идентификатора кэшированного активного указателя, получите координаты указателя с помощью функций getX()
и getY()
, затем сравните эти координаты с вашими кэшированными координатами, чтобы определить, какие указатели переместились.
Используйте функцию getActionIndex()
только с событиями ACTION_POINTER_UP
и ACTION_POINTER_DOWN
. Не используйте эту функцию с событиями ACTION_MOVE
, поскольку она всегда возвращает 0
.
Получить действия MotionEvent
Используйте метод getActionMasked()
или версию совместимости MotionEventCompat.getActionMasked()
чтобы получить действие MotionEvent
. В отличие от более раннего метода getAction()
, getActionMasked()
предназначен для работы с несколькими указателями. Он возвращает действие без индексов указателя. Для действий с допустимым индексом указателя используйте getActionIndex()
чтобы вернуть индекс указателей, связанных с действием, как показано в следующем фрагменте кода:
Котлин
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 -> "" } }
Ява
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 ""; }
Дополнительные ресурсы
Дополнительные сведения о событиях ввода см. в следующих ссылках:
- Обзор входных событий
- Обзор датчиков
- Сделайте пользовательское представление интерактивным
- Перетаскивание и масштабирование