Мультитач-жест — это когда несколько указателей (пальцев) одновременно касаются экрана. В этом документе описывается, как распознавать жесты, включающие несколько указателей.
Отслеживание нескольких указателей
При одновременном касании экрана несколькими указателями система генерирует следующие события касания:
-
ACTION_DOWN: отправляется, когда первый указатель касается экрана. Это запускает жест. Данные указателя для этого указателя всегда находятся по индексу0вMotionEvent. -
ACTION_POINTER_DOWN: отправляется, когда после первого на экран появляются дополнительные указатели. Индекс только что опустившегося указателя можно получить с помощьюgetActionIndex(). -
ACTION_MOVE: отправляется при изменении жеста, затрагивающего любое количество указателей. -
ACTION_POINTER_UP: отправляется, когда поднимается указатель, не являющийся основным. Вы можете получить индекс только что поднявшегося указателя, используяgetActionIndex(). -
ACTION_UP: отправляется, когда последний указатель покидает экран. -
ACTION_CANCEL: указывает на то, что весь жест, включая все указатели, отменен.
Начало и конец жестов
Жест представляет собой последовательность событий, начинающуюся с события ACTION_DOWN и заканчивающуюся событием ACTION_UP или ACTION_CANCEL . Одновременно активен только один жест. Действия DOWN, MOVE, UP и 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) } ... }
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); ... }
Для поддержки нескольких сенсорных указателей можно кэшировать все активные указатели с их идентификаторами в момент события 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
Для получения действия MotionEvent используйте метод getActionMasked() или его совместимую версию MotionEventCompat.getActionMasked() В отличие от предыдущего метода 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 -> "" } }
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 ""; }
Дополнительные ресурсы
Для получения дополнительной информации о входных событиях см. следующие источники:
- Обзор входных событий
- Обзор датчиков
- Сделайте пользовательский вид интерактивным
- Перетаскивание и масштабирование
