Gest wielodotykowy to gest wykonywany jednocześnie kilkoma wskaźnikami (palcami). Z tego dokumentu dowiesz się, jak wykrywać gesty, które wykorzystują wiele wskaźników.
Śledzenie wielu wskaźników
Gdy kilka wskaźników dotyka ekranu jednocześnie, system generuje te zdarzenia dotyku:
ACTION_DOWN
: wysyłany, gdy pierwszy wskaźnik dotyka ekranu. To uruchamia gest. Dane wskaźnika są zawsze w indeksie0
w tablicyMotionEvent
.ACTION_POINTER_DOWN
: wysyłane, gdy dodatkowe wskaźniki pojawiają się na ekranie po pierwszym. Za pomocą parametrugetActionIndex()
możesz uzyskać indeks wskaźnika, który właśnie się przesunął w dół.ACTION_MOVE
: wysyłane, gdy nastąpi zmiana w geście, która obejmuje dowolną liczbę wskaźników.ACTION_POINTER_UP
: wysyłany, gdy wskaźnik inny niż podstawowy przesunie się w górę. Za pomocągetActionIndex()
możesz uzyskać indeks wskaźnika, który właśnie się podniósł.ACTION_UP
: wysyłane, gdy ostatni wskaźnik opuści ekran.ACTION_CANCEL
: oznacza, że całe gesty, w tym wszystkie wskaźniki, zostały anulowane.
Gesty rozpoczęcia i zakończenia
Gest to seria zdarzeń, która zaczyna się zdarzeniem ACTION_DOWN
, a kończy zdarzeniem ACTION_UP
lub ACTION_CANCEL
. W danym momencie może być aktywny tylko jeden gest. Działania DOŁÓŻ, PRZESUŃ, W GÓRĘ i ANULUJ dotyczą całego gestu. Na przykład zdarzenie z wartością ACTION_MOVE
może wskazywać, że w danym momencie wszystkie wskaźniki zostały przesunięte w dół.
Śledź wskaźniki
Aby śledzić poszczególne pozycje wskaźników w ramach MotionEvent
, używaj ich indeksu i identyfikatora.
- Indeks:
MotionEvent
przechowuje wskaźnik do informacji w tablicy. Indeks wskaźnika to jego pozycja w tej tablicy. Większość metodMotionEvent
przyjmuje jako parametr indeks wskaźnika, a nie jego identyfikator. - Identyfikator: każdy wskaźnik ma też mapowanie identyfikatorów, które pozostaje niezmienne w przypadku zdarzeń dotykowych, aby umożliwić śledzenie pojedynczego wskaźnika przez cały czas trwania gestu.
Poszczególne wskaźniki pojawiają się w ramach zdarzenia ruchu w niezdefiniowanej kolejności. Wskaźnik może się zmieniać z jednego zdarzenia na inne, ale jego identyfikator pozostaje niezmienny, dopóki pozostaje aktywny. Użyj metody getPointerId()
, aby uzyskać identyfikator wskaźnika i śledzić go w przypadku wszystkich kolejnych zdarzeń ruchu w ramach gestu. Następnie w przypadku kolejnych zdarzeń ruchu użyj metody findPointerIndex()
, aby uzyskać indeks wskaźnika dla danego identyfikatora wskaźnika w tym zdarzeniu ruchu.
Przykład:
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); ... }
Aby obsługiwać wiele wskaźników dotykowych, możesz zapisać w pamięci podręcznej wszystkie aktywne wskaźniki z ich identyfikatorami w czasie poszczególnych zdarzeń ACTION_POINTER_DOWN
i ACTION_DOWN
. Usuń wskaźniki z pamięci podręcznej w zdarzeniach ACTION_POINTER_UP
i ACTION_UP
. Te identyfikatory zapisane w pamięci podręcznej mogą okazać się przydatne do prawidłowego obsługiwania innych zdarzeń akcji. Na przykład podczas przetwarzania zdarzenia ACTION_MOVE
znajdź indeks każdego zapisanego w pamięci podręcznej aktywnego identyfikatora wskaźnika, pobierz współrzędne wskaźnika za pomocą funkcji getX()
i getY()
, a następnie porównaj te współrzędne z zapisanymi w pamięci podręcznej, aby dowiedzieć się, które wskaźniki się poruszyły.
Funkcji getActionIndex()
używaj tylko w przypadku zdarzeń ACTION_POINTER_UP
i ACTION_POINTER_DOWN
. Nie używaj tej funkcji w przypadku zdarzeń ACTION_MOVE
, ponieważ zawsze zwraca ona wartość 0
.
Pobieranie działań (MotionEvent
)
Aby pobrać działanie MotionEvent
, użyj metody getActionMasked()
lub wersji zgodności MotionEventCompat.getActionMasked()
. W przeciwieństwie do wcześniejszej metody getAction()
metoda getActionMasked()
została zaprojektowana do pracy z wieloma wskaźnikami. Zwraca działanie bez indeksów wskaźnika. W przypadku działań z prawidłowym wskaźnikiem indeksu użyj funkcji getActionIndex()
, aby zwrócić indeks wskaźników powiązanych z działaniem, jak pokazano w tym fragmencie kodu:
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 ""; }
Dodatkowe materiały
Więcej informacji o zdarzeniach związanych z wejściami znajdziesz w tych materiałach:
- Omówienie zdarzeń wejściowych
- Czujniki
- Uzyskiwanie widoku niestandardowego
- Przeciąganie i skalowanie