Śledź ruchy wskaźnika i dotyku

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.

Z tej lekcji dowiesz się, jak śledzić ruch w zdarzeniach dotknięcia.

Nowy onTouchEvent() jest wywoływane razem z ACTION_MOVE zdarzenie za każdym razem, gdy zmieni się bieżąca pozycja kontaktu dotykowego, jego nacisk lub rozmiar. Jako opisane w artykule Wykrywanie typowych gestów, te zdarzenia są rejestrowane w MotionEvent parametr onTouchEvent().

Używanie palców nie zawsze jest najdokładniejszą formą interakcji, Wykrywanie zdarzeń dotknięcia często opiera się bardziej na ruchu niż na prostym kontakcie. Aby ułatwić aplikacjom rozróżnianie gestów związanych z ruchem (np. przesuwania palcem) niezawierających ruchu (np. jedno kliknięcie) upływu ekranu. Upływ dotknięcia odnosi się do odległości w pikselach, jaką użytkownik może uzyskać po dotknięciu powinien przejść, zanim zostanie zinterpretowany jako gest związany z ruchem. Więcej więcej informacji na ten temat znajdziesz w artykule Zarządzanie zdarzeniami dotknięcia w ViewGroup.

Istnieje kilka sposobów śledzenia ruchu za pomocą gestów w zależności od do konkretnych potrzeb aplikacji. Przykłady:

  • Początkowa i końcowa pozycja wskaźnika, np. przesunięcie kursora na ekranie. od punktu A do punktu B.
  • Kierunek, w którym porusza się wskaźnik, określony za pomocą osi X i Y .
  • Historia. Rozmiar historii gestu możesz sprawdzić, wywołując MotionEvent metoda getHistorySize() Następnie można sprawdzić położenie, rozmiar, czas i siłę każdej z reklam wydarzeń historycznych za pomocą funkcji zdarzenia ruchu getHistorical<Value> . Historia jest przydatna podczas renderowania śladu palca użytkownika, takiego jak jak w przypadku rysowania dotykiem. Więcej informacji znajdziesz w dokumentacji MotionEvent.
  • Szybkość, z jaką wskaźnik porusza się po ekranie dotykowym.

Zapoznaj się z tymi powiązanymi materiałami:

Prędkość na torze

Możesz używać gestów opartych na ruchu, które zależą od odległości lub kierunku przesuwa się wskaźnik. Jednak prędkość jest często decydującym czynnikiem w śledzeniu właściwości gestu lub podjęcie decyzji o jego użyciu. Aby zrobić obliczanie szybkości, Android zapewnia VelocityTracker. Funkcja VelocityTracker pomaga śledzić częstotliwość zdarzeń dotknięcia. To jest przydatne dla gestów, których szybkość jest częścią kryteriów gestu, na przykład romans.

Oto przykład, który ilustruje przeznaczenie metod w Interfejs API VelocityTracker:

Kotlin

private const val DEBUG_TAG = "Velocity"

class MainActivity : Activity() {
    private var mVelocityTracker: VelocityTracker? = null

    override fun onTouchEvent(event: MotionEvent): Boolean {

        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                // Reset the velocity tracker back to its initial state.
                mVelocityTracker?.clear()
                // If necessary, retrieve a new VelocityTracker object to watch
                // the velocity of a motion.
                mVelocityTracker = mVelocityTracker ?: VelocityTracker.obtain()
                // Add a user's movement to the tracker.
                mVelocityTracker?.addMovement(event)
            }
            MotionEvent.ACTION_MOVE -> {
                mVelocityTracker?.apply {
                    val pointerId: Int = event.getPointerId(event.actionIndex)
                    addMovement(event)
                    // When you want to determine the velocity, call
                    // computeCurrentVelocity(). Then, call getXVelocity() and
                    // getYVelocity() to retrieve the velocity for each pointer
                    // ID.
                    computeCurrentVelocity(1000)
                    // Log velocity of pixels per second. It's best practice to
                    // use VelocityTrackerCompat where possible.
                    Log.d("", "X velocity: ${getXVelocity(pointerId)}")
                    Log.d("", "Y velocity: ${getYVelocity(pointerId)}")
                }
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                // Return a VelocityTracker object back to be re-used by others.
                mVelocityTracker?.recycle()
                mVelocityTracker = null
            }
        }
        return true
    }
}

Java

public class MainActivity extends Activity {
    private static final String DEBUG_TAG = "Velocity";
        ...
    private VelocityTracker mVelocityTracker = null;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int index = event.getActionIndex();
        int action = event.getActionMasked();
        int pointerId = event.getPointerId(index);

        switch(action) {
            case MotionEvent.ACTION_DOWN:
                if(mVelocityTracker == null) {
                    // Retrieve a new VelocityTracker object to watch the
                    // velocity of a motion.
                    mVelocityTracker = VelocityTracker.obtain();
                }
                else {
                    // Reset the velocity tracker back to its initial state.
                    mVelocityTracker.clear();
                }
                // Add a user's movement to the tracker.
                mVelocityTracker.addMovement(event);
                break;
            case MotionEvent.ACTION_MOVE:
                mVelocityTracker.addMovement(event);
                // When you want to determine the velocity, call
                // computeCurrentVelocity(). Then call getXVelocity() and
                // getYVelocity() to retrieve the velocity for each pointer ID.
                mVelocityTracker.computeCurrentVelocity(1000);
                // Log velocity of pixels per second. It's best practice to use
                // VelocityTrackerCompat where possible.
                Log.d("", "X velocity: " + mVelocityTracker.getXVelocity(pointerId));
                Log.d("", "Y velocity: " + mVelocityTracker.getYVelocity(pointerId));
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                // Return a VelocityTracker object back to be re-used by others.
                mVelocityTracker.recycle();
                break;
        }
        return true;
    }
}

Używaj przechwytywania wskaźnika

Niektóre aplikacje, takie jak gry, klienty pulpitu zdalnego i wirtualizacji, nad kontrolowaniem kursora myszy. Przechwytywanie wskaźnika to funkcja jest dostępna w Androidzie 8.0 (poziom interfejsu API 26) i nowszych. Zapewnia to kontrolę wyświetlanie wszystkich zdarzeń myszy w zaznaczonym widoku aplikacji.

Poproś o zdjęcie wskaźnika

Widok w aplikacji może poprosić o przechwycenie wskaźnika tylko wtedy, gdy hierarchia widoków jest zaznaczony. Z tego powodu poproś o przechwycenie wskaźnika, gdy określonego działania użytkownika w widoku danych, np. podczas onClick() lub w elemencie onWindowFocusChanged() modułu obsługi zdarzeń Twojej aktywności.

Aby poprosić o przechwycenie wskaźnika, wywołaj funkcję requestPointerCapture() dla widoku. Poniższy przykładowy kod pokazuje, jak poprosić o wskaźnik Przechwytuje się, gdy użytkownik kliknie film.

Kotlin

fun onClick(view: View) {
    view.requestPointerCapture()
}

Java

@Override
public void onClick(View view) {
    view.requestPointerCapture();
}

Gdy żądanie przechwycenia wskaźnika zostanie zrealizowane, Android wywołuje onPointerCaptureChange(true) System dostarcza zdarzenia myszy do aktywnego widoku aplikacji, znajduje się w tej samej hierarchii widoków co widok, z którego przechwycono obraz. Inny powód do czasu udostępnienia funkcji przechwytywania aplikacji nie odbierają zdarzeń myszy, w tym ACTION_OUTSIDE zdarzeń. Android dostarcza zdarzenia wskaźnika ze źródeł innych niż mysz, ale wskaźnik myszy nie jest już widoczny.

Obsługa przechwyconych zdarzeń wskaźnika

Gdy widok zostanie przechwycony wskaźnikiem, Android przesyła zdarzeń myszy. Zawężony widok może obsługiwać zdarzenia, wykonując jedną z następujące zadania:

Poniższy przykładowy kod pokazuje, jak zaimplementować onCapturedPointerEvent(MotionEvent):

Kotlin

override fun onCapturedPointerEvent(motionEvent: MotionEvent): Boolean {
    // Get the coordinates required by your app.
    val verticalOffset: Float = motionEvent.y
    // Use the coordinates to update your view and return true if the event is
    // successfully processed.
    return true
}

Java

@Override
public boolean onCapturedPointerEvent(MotionEvent motionEvent) {
  // Get the coordinates required by your app.
  float verticalOffset = motionEvent.getY();
  // Use the coordinates to update your view and return true if the event is
  // successfully processed.
  return true;
}

Poniższy przykładowy kod pokazuje, jak zarejestrować OnCapturedPointerListener:

Kotlin

myView.setOnCapturedPointerListener { view, motionEvent ->
    // Get the coordinates required by your app.
    val horizontalOffset: Float = motionEvent.x
    // Use the coordinates to update your view and return true if the event is
    // successfully processed.
    true
}

Java

myView.setOnCapturedPointerListener(new View.OnCapturedPointerListener() {
  @Override
  public boolean onCapturedPointer (View view, MotionEvent motionEvent) {
    // Get the coordinates required by your app.
    float horizontalOffset = motionEvent.getX();
    // Use the coordinates to update your view and return true if the event is
    // successfully processed.
    return true;
  }
});

Niezależnie od tego, czy korzystasz z widoku niestandardowego, czy rejestrujesz detektor, widok otrzymuje MotionEvent ze współrzędnymi wskaźnika, które określają ruchy względne, np. X lub delta Y, podobnie jak współrzędne podawane przez kulkę. Dostępne opcje pobierz współrzędne za pomocą getX() i getY()

Zwolnij zapis wskaźnika

Widok w aplikacji może zwolnić przechwycony wskaźnik przez połączenie releasePointerCapture() jak w tym przykładowym kodzie:

Kotlin

override fun onClick(view: View) {
    view.releasePointerCapture()
}

Java

@Override
public void onClick(View view) {
    view.releasePointerCapture();
}

System może odebrać zdjęcie bez Twojej wyraźnej zgody użytkownika. Wywołuję funkcję releasePointerCapture(), często dlatego, że hierarchia widoków który zawiera widok, w którym żądania są przechwytywane.