Z tej lekcji dowiesz się, jak śledzić ruch w zdarzeniach dotknięcia.
Nowe onTouchEvent()
jest wywoływane ze zdarzeniem ACTION_MOVE
za każdym razem, gdy zmieni się bieżąca pozycja kontaktu, nacisk lub rozmiar. Jak opisano w sekcji Wykrywanie typowych gestów, wszystkie te zdarzenia są rejestrowane w parametrze MotionEvent
parametru onTouchEvent()
.
Dotyk palcem nie zawsze jest najdokładniejszą formą interakcji, dlatego wykrywanie 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) i nieporuszających (np. jedno dotknięcie), Android umożliwia upływ dotyku. Upływ dotyku odnosi się do odległości w pikselach, jaką użytkownik może wykonywać dotyk, zanim gest zostanie zinterpretowany jako gest związany z ruchem. Więcej informacji na ten temat znajdziesz w artykule Zarządzanie zdarzeniami dotknięcia w grupie ViewGroup.
Istnieje kilka sposobów śledzenia ruchu za pomocą gestów w zależności od potrzeb aplikacji. Przykłady:
- Położenie początkowe i końcowe wskaźnika, np. przesunięcie obiektu na ekranie z punktu A do punktu B.
- Kierunek, w którym porusza się wskaźnik, określony za pomocą współrzędnych X i Y.
- Historia. Rozmiar historii gestu możesz sprawdzić, wywołując metodę
MotionEvent
getHistorySize()
. Korzystając z metodgetHistorical<Value>
zdarzenia ruchu, możesz uzyskać informacje o położeniu, rozmiarze, czasie i siły nacisku każdego zdarzenia historycznego. Historia jest przydatna podczas renderowania śladu palca użytkownika, np. do rysowania dotykowego. Więcej informacji znajdziesz w dokumentacjiMotionEvent
. - 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żyć gestu związanego z ruchem opartym na odległości lub kierunku pokonywania wskaźnika. Jednak to prędkość często decyduje o jego Aby ułatwić obliczanie szybkości, Android udostępnia klasę VelocityTracker
.
Funkcja VelocityTracker
pomaga śledzić częstotliwość zdarzeń dotknięcia. Przydaje się to przy gestach, których szybkość jest jednym z kryteriów gestu, takich jak gesty.
Oto przykład ilustrujący przeznaczenie metod w interfejsie 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, mogą korzystać z możliwości kontrolowania wskaźnika myszy. Przechwytywanie wskaźnika to funkcja dostępna w Androidzie 8.0 (poziom interfejsu API 26) i nowszych, która zapewnia tę kontrolę przez wyświetlanie wszystkich zdarzeń myszy w wybranym widoku aplikacji.
Poproś o zdjęcie wskaźnika
Widok w aplikacji może poprosić o przechwycenie wskaźnika tylko wtedy, gdy zawiera go hierarchia widoków. Dlatego poproś o przechwytywanie wskaźnika, gdy w widoku istnieje określone działanie użytkownika, np. podczas zdarzenia onClick()
lub w module obsługi zdarzeń onWindowFocusChanged()
w Twojej aktywności.
Aby poprosić o przechwycenie wskaźnika, wywołaj w widoku metodę requestPointerCapture()
. Poniższy przykładowy kod pokazuje, jak zażądać przechwytywania wskaźnika, gdy użytkownik kliknie widok:
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ła metodę onPointerCaptureChange(true)
.
System dostarcza zdarzenia myszy do aktywnego widoku aplikacji, o ile znajduje się ona w tej samej hierarchii widoków co widok, z którego przechwycono obraz. Inne aplikacje (w tym zdarzenia ACTION_OUTSIDE
) nie odbierają zdarzeń myszy do czasu udostępnienia przechwycenia. Android dostarcza zdarzenia wskaźnika ze źródeł innych niż mysz w zwykły sposób, ale wskaźnik myszy nie jest już widoczny.
Obsługa przechwyconych zdarzeń wskaźnika
Gdy widok uzyska przechwycenie wskaźnika, Android dostarczy zdarzenia myszy. Widok aktywny może obsługiwać zdarzenia, wykonując jedną z tych czynności:
- Jeśli korzystasz z widoku niestandardowego, zastąp parametr
onCapturedPointerEvent(MotionEvent)
. - W przeciwnym razie zarejestruj
OnCapturedPointerListener
.
Ten przykładowy kod pokazuje, jak wdrożyć 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; }
Ten 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, Twój widok otrzymuje MotionEvent
ze współrzędnymi wskaźnika określającymi ruchy względne, np. delta X lub Y, podobnie jak współrzędne dostarczane przez kulkę. Aby pobrać współrzędne, możesz użyć właściwości getX()
i getY()
.
Zwolnij zapis wskaźnika
Widok w aplikacji może zwolnić przechwycony wskaźnik przez wywołanie metody releasePointerCapture()
, jak pokazano 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ć przechwycony widok z widoku bez konieczności jawnego wywoływania funkcji releasePointerCapture()
. Często dzieje się tak dlatego, że hierarchia widoków danych zawierająca widok, który obejmuje przechwytywanie żądań, traci fokus.