Tutorial ini menjelaskan cara melacak gerakan dalam peristiwa sentuhan.
A new
onTouchEvent()
dipicu dengan peristiwa
ACTION_MOVE
setiap kali posisi kontak sentuh saat ini, tekanan, atau ukuran berubah. Seperti
dijelaskan dalam Mendeteksi gestur umum, semua
peristiwa ini dicatat dalam
MotionEvent parameter dari
onTouchEvent().
Karena sentuhan berbasis jari tidak selalu menjadi bentuk interaksi yang paling tepat, deteksi peristiwa sentuhan seringkali lebih didasarkan pada gerakan daripada kontak sederhana. Untuk membantu aplikasi membedakan gestur berbasis gerakan (seperti geser) dengan gestur non-gerakan (seperti satu ketukan), Android menyertakan gagasan touch slop. Touch slop merujuk pada jarak dalam piksel yang dapat ditelusuri dengan sentuhan pengguna sebelum gestur diartikan sebagai gestur berbasis gerakan. Untuk mengetahui informasi selengkapnya tentang topik ini, lihat Mengelola peristiwa sentuhan di ViewGroup.
Ada beberapa cara untuk melacak gerakan dalam gestur, bergantung pada kebutuhan aplikasi Anda. Berikut adalah contohnya:
- Posisi awal dan akhir pointer, seperti memindahkan objek di layar dari titik A ke titik B.
- Arah pointer berjalan, seperti yang ditentukan oleh koordinat X dan Y.
- Histori. Anda dapat menemukan ukuran histori gestur dengan memanggil metode
MotionEventgetHistorySize(). Anda kemudian dapat memperoleh posisi, ukuran, waktu, dan tekanan dari setiap peristiwa historis dengan menggunakan peristiwa gerakgetHistorical<Value>metode. Histori akan berguna saat melakukan proses rendering pada jejak jari pengguna, seperti untuk menggambar dengan sentuhan. Lihat referensiMotionEventuntuk mengetahui detailnya. - Kecepatan pointer saat bergerak di atas layar sentuh.
Lihat referensi terkait berikut:
Melacak kecepatan
Anda dapat membuat gestur berbasis gerakan yang didasarkan pada jarak atau arah yang dilalui pointer. Namun, kecepatan sering menjadi faktor penentu dalam melacak karakteristik gestur atau memutuskan apakah gestur itu terjadi. Untuk mempermudah
penghitungan kecepatan, Android menyediakan
VelocityTracker class.
VelocityTracker membantu Anda melacak kecepatan peristiwa sentuhan. Hal ini berguna untuk gestur di mana kecepatan menjadi bagian dari kriteria gestur tersebut, seperti fling.
Berikut adalah contoh yang menggambarkan tujuan metode dalam 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; } }
Menggunakan rekaman pointer
Beberapa aplikasi, seperti game dan klien desktop jarak jauh serta virtualisasi, diuntungkan karena dapat dikontrol melalui pointer mouse. Rekaman pointer adalah fitur yang tersedia di Android 8.0 (API level 26) dan versi lebih baru yang menyediakan kontrol ini dengan mengirimkan semua peristiwa mouse ke tampilan fokus di aplikasi Anda.
Meminta rekaman pointer
Tampilan di aplikasi Anda dapat meminta rekaman pointer hanya saat hierarki tampilan yang memuatnya memiliki fokus. Untuk alasan ini, minta rekaman pointer saat ada tindakan pengguna tertentu pada tampilan, seperti selama peristiwa
onClick()
atau dalam pengendali peristiwa
onWindowFocusChanged()
dari aktivitas Anda.
Untuk meminta rekaman pointer, panggil metode
requestPointerCapture()
pada tampilan. Contoh kode berikut menunjukkan cara meminta rekaman pointer saat pengguna mengklik tampilan:
Kotlin
fun onClick(view: View) { view.requestPointerCapture() }
Java
@Override public void onClick(View view) { view.requestPointerCapture(); }
Setelah permintaan untuk merekam pointer berhasil, Android akan memanggil
onPointerCaptureChange(true).
Sistem akan mengirimkan peristiwa mouse ke tampilan fokus di aplikasi Anda selama berada dalam hierarki tampilan yang sama dengan tampilan yang meminta rekaman. Aplikasi lain akan berhenti menerima peristiwa mouse hingga rekaman dirilis, termasuk
ACTION_OUTSIDE
peristiwa. Android akan mengirimkan peristiwa pointer dari sumber selain mouse secara normal, tetapi pointer mouse tidak akan terlihat lagi.
Menangani peristiwa pointer yang direkam
Setelah tampilan berhasil memperoleh rekaman pointer, Android akan mengirimkan peristiwa mouse. Tampilan fokus Anda dapat menangani peristiwa dengan melakukan salah satu tugas berikut:
- Jika Anda menggunakan tampilan kustom, ganti
onCapturedPointerEvent(MotionEvent). - Jika tidak, daftarkan
OnCapturedPointerListener.
Contoh kode berikut menunjukkan cara mengimplementasikan
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; }
Contoh kode berikut menunjukkan cara mendaftarkan
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; } });
Baik menggunakan tampilan kustom maupun mendaftarkan pemroses, tampilan Anda akan menerima MotionEvent dengan koordinat pointer yang menentukan gerakan relatif seperti delta X atau Y, mirip dengan koordinat yang dikirimkan oleh perangkat trackball. Anda dapat
mengambil koordinat menggunakan
getX() dan
getY().
Merilis rekaman pointer
Tampilan di aplikasi Anda dapat merilis rekaman pointer dengan memanggil
releasePointerCapture(),
seperti ditunjukkan dalam contoh kode berikut:
Kotlin
override fun onClick(view: View) { view.releasePointerCapture() }
Java
@Override public void onClick(View view) { view.releasePointerCapture(); }
Sistem dapat mengambil rekaman dari tampilan tanpa Anda secara eksplisit memanggil releasePointerCapture(), biasanya karena hierarki tampilan yang berisi tampilan yang meminta rekaman kehilangan fokus.