Wykrywanie typowych gestów

Wypróbuj sposób tworzenia wiadomości
Jetpack Compose to zalecany zestaw narzędzi UI na Androida. Dowiedz się, jak w funkcji tworzenia wiadomości używać dotyku i wprowadzania tekstu.

Gest dotyku występuje, gdy użytkownik zbliży co najmniej 1 palec na ekranie dotykowym, a aplikacja zinterpretuje ten wzorzec dotknięć jako gest. OK Wykrywanie gestów dzieli się na 2 fazy:

  1. Zbieram dane zdarzeń dotknięcia.
  2. Interpretacja danych w celu określenia, czy spełniają one kryteria gestów obsługiwanych przez aplikację.

Zajęcia na AndroidzieX

Przykłady w tym dokumencie wykorzystują GestureDetectorCompat oraz MotionEventCompat zajęcia. Zajęcia te są dostępne na urządzeniach z Androidem X Biblioteka. Tam, gdzie to możliwe, używaj klas AndroidaX, aby zapewnić zgodność z starszych urządzeń. MotionEventCompat nie zastępuje MotionEvent zajęcia. Udostępnia on statyczne metody narzędzia, którym przekazujesz MotionEvent obiekt, aby otrzymać powiązane z nim działanie .

Zbieranie danych

Gdy użytkownik nałożyć na ekran co najmniej 1 palcem, oddzwanianie onTouchEvent() w widoku, w którym są rejestrowane zdarzenia dotknięcia. Dla każdej sekwencji dotyku zdarzeń takich jak pozycja, ciśnienie, wielkość i dodawanie palec, który jest rozpoznawany jako gest, onTouchEvent() to kilka razy uruchamiany.

Gest uruchamia się, gdy użytkownik po raz pierwszy dotyka ekranu, i jest kontynuowany system śledzi położenie palca użytkownika i kończy się nagrywanie ostatniego zdarzenia polegającego na opuszczeniu ekranu ostatniego palca użytkownika. W trakcie tej interakcji reklama MotionEvent dostarczała wiadomości onTouchEvent() podaje szczegóły każdej interakcji. Twoja aplikacja może użyć danych dostarczonych przez MotionEvent do określenia, czy gestami, na których jest dla niego ważny gest.

Rejestrowanie zdarzeń dotknięcia w ramach aktywności lub widoku

Aby przechwytywać zdarzenia dotyku w Activity lub View, zastąp wywołanie zwrotne onTouchEvent().

W poniższym fragmencie kodu getAction() aby wyodrębnić z parametru event działanie wykonywane przez użytkownika. Dzięki temu otrzymujesz nieprzetworzone dane, dzięki którym możesz określić, czy gest jest dla Ciebie ważny na temat.

Kotlin

class MainActivity : Activity() {
    ...
    // This example shows an Activity. You can use the same approach if you are 
    // subclassing a View.
    override fun onTouchEvent(event: MotionEvent): Boolean {
        return when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                Log.d(DEBUG_TAG, "Action was DOWN")
                true
            }
            MotionEvent.ACTION_MOVE -> {
                Log.d(DEBUG_TAG, "Action was MOVE")
                true
            }
            MotionEvent.ACTION_UP -> {
                Log.d(DEBUG_TAG, "Action was UP")
                true
            }
            MotionEvent.ACTION_CANCEL -> {
                Log.d(DEBUG_TAG, "Action was CANCEL")
                true
            }
            MotionEvent.ACTION_OUTSIDE -> {
                Log.d(DEBUG_TAG, "Movement occurred outside bounds of current screen element")
                true
            }
            else -> super.onTouchEvent(event)
        }
    }
}

Java

public class MainActivity extends Activity {
...
// This example shows an Activity. You can use the same approach if you are
// subclassing a View.
@Override
public boolean onTouchEvent(MotionEvent event){
    switch(event.getAction()) {
        case (MotionEvent.ACTION_DOWN) :
            Log.d(DEBUG_TAG,"Action was DOWN");
            return true;
        case (MotionEvent.ACTION_MOVE) :
            Log.d(DEBUG_TAG,"Action was MOVE");
            return true;
        case (MotionEvent.ACTION_UP) :
            Log.d(DEBUG_TAG,"Action was UP");
            return true;
        case (MotionEvent.ACTION_CANCEL) :
            Log.d(DEBUG_TAG,"Action was CANCEL");
            return true;
        case (MotionEvent.ACTION_OUTSIDE) :
            Log.d(DEBUG_TAG,"Movement occurred outside bounds of current screen element");
            return true;
        default :
            return super.onTouchEvent(event);
    }
}

Gdy użytkownik klika ten kod, tworzy on w Logcat komunikat podobny do tego: dotknięcia i przytrzymuje i przeciąga:

GESTURES D   Action was DOWN
GESTURES D   Action was UP
GESTURES D   Action was MOVE

Możesz też samodzielnie przetwarzać zdarzenia, aby: określają, czy jest to gest, który musisz wykonać. Jeśli jednak aplikacja używa typowych gestów, takich jak dwukrotne kliknięcie, dotyk trzymać, rzucać i tak dalej, możesz skorzystać z GestureDetector zajęcia. GestureDetector ułatwia wykrywanie częstych problemów bez konieczności samodzielnego przetwarzania poszczególnych zdarzeń dotknięcia. To jest omówiono dokładnie w sekcji Wykrywanie gestów.

Rejestruj zdarzenia dotknięcia w jednym widoku

Zamiast onTouchEvent() możesz dołączyć plik View.OnTouchListener do dowolnego obiektu View za pomocą funkcji setOnTouchListener() . Dzięki temu można nasłuchiwać zdarzeń dotknięcia bez podklasyfikowania istniejące View, jak w tym przykładzie:

Kotlin

findViewById<View>(R.id.my_view).setOnTouchListener { v, event ->
    // Respond to touch events.
    true
}

Java

View myView = findViewById(R.id.my_view);
myView.setOnTouchListener(new OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event) {
        // Respond to touch events.
        return true;
    }
});

Uważaj na utworzenie detektora, który zwróci wartość false dla ACTION_DOWN. Jeśli to zrobisz, odbiornik nie zostanie wywołany ACTION_MOVE i Sekwencja ACTION_UP zdarzeń. Dzieje się tak, ponieważ ACTION_DOWN jest punktem wyjścia dla wszystkich dotknięcia.

Jeśli tworzysz widok niestandardowy, możesz zastąpić widok onTouchEvent(), jak opisano wcześniej.

Wykrywanie gestów

Android udostępnia klasę GestureDetector do wykrywania typowych treści gestami. Obsługuje ona m.in. takie gesty, onDown(), onLongPress(), oraz onFling() Możesz używać GestureDetector w połączeniu z Metoda onTouchEvent() opisana wcześniej.

Wykryj wszystkie obsługiwane gesty

Podczas tworzenia instancji obiektu GestureDetectorCompat jedna z metod to klasa implementująca GestureDetector.OnGestureListener za pomocą prostego interfejsu online. GestureDetector.OnGestureListener powiadamia użytkowników, gdy konkretne zdarzenie dotknięcia. Aby umożliwić wydawcom GestureDetector do odbierania zdarzeń, zastąpić widok lub metody onTouchEvent() aktywności i przekazywać wszystkie zaobserwowane zdarzenia do instancji wzorca.

W tym fragmencie kodu zwracana jest wartość true z parametru poszczególne metody on<TouchEvent> wskazują, że obsługiwane jest zdarzenie dotknięcia. Wartość zwrotna równa false pomija zdarzenia na stosie widoku aż do kliknięcia.

Jeśli uruchomisz ten fragment kodu w aplikacji testowej, możesz sprawdzić, są wywoływane podczas interakcji z ekranem dotykowym oraz zawartość MotionEvent dotyczy każdego zdarzenia dotknięcia. Zobaczysz wówczas ile danych jest generowanych na potrzeby prostych interakcji.

Kotlin

private const val DEBUG_TAG = "Gestures"

class MainActivity :
        Activity(),
        GestureDetector.OnGestureListener,
        GestureDetector.OnDoubleTapListener {

    private lateinit var mDetector: GestureDetectorCompat

    // Called when the activity is first created.
    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Instantiate the gesture detector with the
        // application context and an implementation of
        // GestureDetector.OnGestureListener.
        mDetector = GestureDetectorCompat(this, this)
        // Set the gesture detector as the double-tap
        // listener.
        mDetector.setOnDoubleTapListener(this)
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        return if (mDetector.onTouchEvent(event)) {
            true
        } else {
            super.onTouchEvent(event)
        }
    }

    override fun onDown(event: MotionEvent): Boolean {
        Log.d(DEBUG_TAG, "onDown: $event")
        return true
    }

    override fun onFling(
            event1: MotionEvent,
            event2: MotionEvent,
            velocityX: Float,
            velocityY: Float
    ): Boolean {
        Log.d(DEBUG_TAG, "onFling: $event1 $event2")
        return true
    }

    override fun onLongPress(event: MotionEvent) {
        Log.d(DEBUG_TAG, "onLongPress: $event")
    }

    override fun onScroll(
            event1: MotionEvent,
            event2: MotionEvent,
            distanceX: Float,
            distanceY: Float
    ): Boolean {
        Log.d(DEBUG_TAG, "onScroll: $event1 $event2")
        return true
    }

    override fun onShowPress(event: MotionEvent) {
        Log.d(DEBUG_TAG, "onShowPress: $event")
    }

    override fun onSingleTapUp(event: MotionEvent): Boolean {
        Log.d(DEBUG_TAG, "onSingleTapUp: $event")
        return true
    }

    override fun onDoubleTap(event: MotionEvent): Boolean {
        Log.d(DEBUG_TAG, "onDoubleTap: $event")
        return true
    }

    override fun onDoubleTapEvent(event: MotionEvent): Boolean {
        Log.d(DEBUG_TAG, "onDoubleTapEvent: $event")
        return true
    }

    override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
        Log.d(DEBUG_TAG, "onSingleTapConfirmed: $event")
        return true
    }

}

Java

public class MainActivity extends Activity implements
        GestureDetector.OnGestureListener,
        GestureDetector.OnDoubleTapListener{

    private static final String DEBUG_TAG = "Gestures";
    private GestureDetectorCompat mDetector;

    // Called when the activity is first created.
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Instantiate the gesture detector with the
        // application context and an implementation of
        // GestureDetector.OnGestureListener.
        mDetector = new GestureDetectorCompat(this,this);
        // Set the gesture detector as the double-tap
        // listener.
        mDetector.setOnDoubleTapListener(this);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event){
        if (this.mDetector.onTouchEvent(event)) {
            return true;
        }
        return super.onTouchEvent(event);
    }

    @Override
    public boolean onDown(MotionEvent event) {
        Log.d(DEBUG_TAG,"onDown: " + event.toString());
        return true;
    }

    @Override
    public boolean onFling(MotionEvent event1, MotionEvent event2,
            float velocityX, float velocityY) {
        Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString());
        return true;
    }

    @Override
    public void onLongPress(MotionEvent event) {
        Log.d(DEBUG_TAG, "onLongPress: " + event.toString());
    }

    @Override
    public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
            float distanceY) {
        Log.d(DEBUG_TAG, "onScroll: " + event1.toString() + event2.toString());
        return true;
    }

    @Override
    public void onShowPress(MotionEvent event) {
        Log.d(DEBUG_TAG, "onShowPress: " + event.toString());
    }

    @Override
    public boolean onSingleTapUp(MotionEvent event) {
        Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString());
        return true;
    }

    @Override
    public boolean onDoubleTap(MotionEvent event) {
        Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString());
        return true;
    }

    @Override
    public boolean onDoubleTapEvent(MotionEvent event) {
        Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString());
        return true;
    }

    @Override
    public boolean onSingleTapConfirmed(MotionEvent event) {
        Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString());
        return true;
    }
}

Wykrywanie zestawu obsługiwanych gestów

Jeśli chcesz przetworzyć tylko kilka gestów, możesz rozszerzyć GestureDetector.SimpleOnGestureListener zamiast implementować GestureDetector.OnGestureListener. za pomocą prostego interfejsu online.

GestureDetector.SimpleOnGestureListener udostępnia dla wszystkich on<TouchEvent> metod, zwracając false. Umożliwia to zastąpienie tylko metod na których Ci zależy. Na przykład ten fragment kodu tworzy klasę, która rozszerza GestureDetector.SimpleOnGestureListener i zastąpienia onFling() i onDown().

Niezależnie od tego, czy korzystasz z usługi GestureDetector.OnGestureListener czy GestureDetector.SimpleOnGestureListener, najlepiej jest zaimplementuj metodę onDown(), która zwraca true. Ten jest, że wszystkie gesty zaczynają się od komunikatu onDown(). Jeśli zwróć false od: onDown(), jako GestureDetector.SimpleOnGestureListener domyślnie zakłada, że chcesz zignorować resztę gestu, a inne metody GestureDetector.OnGestureListener nie są wywoływane. Może to spowodować nieoczekiwane problemy z aplikacją. Zwróć tylko false od onDown(), jeśli naprawdę chcesz zignorować cały gest.

Kotlin

private const val DEBUG_TAG = "Gestures"

class MainActivity : Activity() {

    private lateinit var mDetector: GestureDetectorCompat

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mDetector = GestureDetectorCompat(this, MyGestureListener())
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        mDetector.onTouchEvent(event)
        return super.onTouchEvent(event)
    }

    private class MyGestureListener : GestureDetector.SimpleOnGestureListener() {

        override fun onDown(event: MotionEvent): Boolean {
            Log.d(DEBUG_TAG, "onDown: $event")
            return true
        }

        override fun onFling(
                event1: MotionEvent,
                event2: MotionEvent,
                velocityX: Float,
                velocityY: Float
        ): Boolean {
            Log.d(DEBUG_TAG, "onFling: $event1 $event2")
            return true
        }
    }
}

Java

public class MainActivity extends Activity {

    private GestureDetectorCompat mDetector;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDetector = new GestureDetectorCompat(this, new MyGestureListener());
    }

    @Override
    public boolean onTouchEvent(MotionEvent event){
        if (this.mDetector.onTouchEvent(event)) {
              return true;
        }
        return super.onTouchEvent(event);
    }

    class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
        private static final String DEBUG_TAG = "Gestures";

        @Override
        public boolean onDown(MotionEvent event) {
            Log.d(DEBUG_TAG,"onDown: " + event.toString());
            return true;
        }

        @Override
        public boolean onFling(MotionEvent event1, MotionEvent event2,
                float velocityX, float velocityY) {
            Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString());
            return true;
        }
    }
}

Dodatkowe materiały