Obsługa gestów wielodotykowych

Wypróbuj sposób tworzenia wiadomości
Jetpack Compose to zalecany zestaw narzędzi UI na Androida. Dowiedz się, jak korzystać z dotyku i wprowadzania w sekcji Utwórz

Gest wielodotykowy polega na dotknięciu ekranu kilkoma wskaźnikami (palcami) w tym samym czasie. W tym dokumencie opisujemy, jak wykrywać gesty zawierające wiele wskaźników.

Śledź wiele wskaźników

Gdy wiele wskaźników dotknie ekranu jednocześnie, system wygeneruje te zdarzenia dotknięcia:

  • ACTION_DOWN: wysyłane po dotknięciu ekranu pierwszym wskaźnikiem. Spowoduje to uruchomienie gestu. Dane wskaźnika dla tego wskaźnika znajdują się zawsze w indeksie 0 w MotionEvent.
  • ACTION_POINTER_DOWN: wysyłane, gdy na ekranie pojawią się dodatkowe wskaźniki po pierwszym. Indeks wskaźnika, który właśnie przestał działać, możesz uzyskać za pomocą właściwości getActionIndex().
  • ACTION_MOVE: wysyłana, gdy zmiana zachodzi w geście, uwzględniająca dowolną liczbę wskaźników.
  • ACTION_POINTER_UP: wysyłana, gdy pojawi się wskaźnik inny niż główny. Indeks wskaźnika, który właśnie wzrósł, możesz uzyskać za pomocą właściwości getActionIndex().
  • ACTION_UP: wysyłane, gdy ostatni wskaźnik opuszcza ekran.
  • ACTION_CANCEL: wskazuje, że cały gest, w tym wszystkie wskaźniki, został anulowany.

Gesty rozpoczynania i kończenia

Gest to seria zdarzeń rozpoczynających się od zdarzenia ACTION_DOWN i kończących się zdarzeniem ACTION_UP albo ACTION_CANCEL. W danej chwili jest tylko 1 aktywny gest. Działania W DÓŁ, PRZENIEŚ, W GÓRĘ i ANULUJ dotyczą całego gestu. Na przykład zdarzenie z parametrem ACTION_MOVE może wskazywać na ruch wszystkich wskaźników w danym momencie.

Śledzenie wskaźników

Używaj indeksu i identyfikatora wskaźnika, aby śledzić poszczególne pozycje wskaźników w obiekcie MotionEvent.

  • Indeks: MotionEvent przechowuje informacje o wskaźniku w tablicy. Indeks wskaźnika to jego pozycja w tej tablicy. Większość metod MotionEvent wykorzystuje indeks wskaźnika jako parametr, a nie identyfikator wskaźnika.
  • Identyfikator: każdy wskaźnik ma też mapowanie identyfikatora, które jest trwałe w przypadku zdarzeń dotknięcia, co umożliwia śledzenie pojedynczego wskaźnika przez cały gest.

Poszczególne wskaźniki są wyświetlane w ramach zdarzenia ruchu w nieokreślonej kolejności. W związku z tym indeks wskaźnika może się zmieniać z jednego zdarzenia w kolejne, ale gwarantuje, że pozostaje on niezmieniony, dopóki wskaźnik pozostaje aktywny. Aby uzyskać identyfikator wskaźnika, użyj metody getPointerId(), aby śledzić go we wszystkich kolejnych zdarzeniach ruchu związanych z gestem. Następnie dla kolejnych zdarzeń ruchu użyj metody findPointerIndex(), aby uzyskać indeks wskaźnika dla danego identyfikatora wskaźnika w danym zdarzeniu ruchu. Na 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 identyfikatorami poszczególnych zdarzeń ACTION_POINTER_DOWN i ACTION_DOWN. Usuń z pamięci podręcznej wskaźniki związane z zdarzeniami ACTION_POINTER_UP i ACTION_UP. Identyfikatory z pamięci podręcznej mogą się przydać do prawidłowej obsługi innych zdarzeń działań. Na przykład podczas przetwarzania zdarzenia ACTION_MOVE znajdź indeks każdego aktywnego identyfikatora wskaźnika zapisanego w pamięci podręcznej, pobierz współrzędne wskaźnika za pomocą funkcji getX() i getY(), a następnie porównaj te współrzędne ze współrzędnymi w pamięci podręcznej, aby sprawdzić, które wskaźniki zostały przeniesione.

Używaj funkcji getActionIndex() tylko ze zdarzeniami ACTION_POINTER_UP i ACTION_POINTER_DOWN. Nie używaj tej funkcji ze zdarzeniami ACTION_MOVE, ponieważ zawsze zwraca wartość 0.

Pobierz działania (MotionEvent)

Aby pobrać działanie obiektu MotionEvent, użyj metody getActionMasked() lub wersji zgodności MotionEventCompat.getActionMasked(). W odróżnieniu od wcześniejszej metody getAction() getActionMasked() służy do pracy z wieloma wskaźnikami. Zwraca działanie bez indeksów. W przypadku działań z prawidłowym indeksem użyj funkcji getActionIndex(), aby zwrócić indeks wskaźników powiązanych z działaniem, jak pokazano we 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 "";
}
Rysunek 1. Wzory do rysowania za pomocą funkcji multi-touch.

Dodatkowe materiały

Więcej informacji o zdarzeniach wejściowych znajdziesz w tych materiałach: