Gestur sentuh terjadi saat pengguna meletakkan satu jari atau lebih pada layar sentuh dan aplikasi Anda mengartikan pola sentuhan ini sebagai gestur. Ada dua fase untuk deteksi gestur:
- Mengumpulkan data peristiwa sentuh.
- Menginterpretasikan data untuk menentukan apakah telah memenuhi kriteria untuk gestur yang didukung aplikasi Anda.
Class AndroidX
Contoh dalam dokumen ini menggunakan class
GestureDetectorCompat
dan
MotionEventCompat. Class ini berada di AndroidX Library. Gunakan class AndroidX jika memungkinkan untuk memberikan kompatibilitas dengan perangkat lama.
MotionEventCompat bukan pengganti class
MotionEvent. Class ini menyediakan metode utilitas statis untuk meneruskan objek MotionEvent Anda untuk menerima tindakan yang terkait dengan peristiwa tersebut.
Mengumpulkan data
Saat pengguna menempatkan satu atau beberapa jari di layar, hal ini akan memicu callback onTouchEvent() pada tampilan yang menerima peristiwa sentuhan. Untuk setiap urutan peristiwa sentuhan—seperti posisi, tekanan, ukuran, dan penambahan jari lain—yang diidentifikasi sebagai gestur, onTouchEvent() akan diaktifkan beberapa kali.
Gestur dimulai saat pengguna pertama kali menyentuh layar, berlanjut saat sistem melacak posisi jari pengguna, dan berakhir dengan menangkap peristiwa terakhir saat jari terakhir pengguna meninggalkan layar.
Selama interaksi ini, MotionEvent yang dikirimkan ke onTouchEvent() memberikan detail setiap interaksi. Aplikasi Anda dapat menggunakan data yang disediakan oleh MotionEvent untuk menentukan apakah terjadi gestur yang terkait dengannya.
Menangkap peristiwa sentuhan untuk Aktivitas atau Tampilan
Untuk mencegat peristiwa sentuhan di Activity atau
View, ganti callback onTouchEvent().
Cuplikan kode berikut menggunakan
getAction()
untuk mengekstrak tindakan yang dilakukan pengguna dari parameter event.
Hal ini akan memberi Anda data mentah yang Anda butuhkan untuk menentukan apakah gestur yang terkait dengan Anda terjadi.
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); } }
Kode ini menghasilkan pesan seperti berikut di Logcat saat pengguna mengetuk, menyentuh & menahan, dan menarik:
GESTURES D Action was DOWN GESTURES D Action was UP GESTURES D Action was MOVE
Untuk gestur kustom, Anda dapat melakukan pemrosesan sendiri terhadap peristiwa ini untuk menentukan apakah peristiwa tersebut mewakili gestur yang perlu Anda tangani. Namun, jika aplikasi Anda menggunakan gestur umum, seperti ketuk dua kali, sentuh & tahan, lempar, dan sebagainya, Anda dapat memanfaatkan class GestureDetector. GestureDetector memudahkan Anda mendeteksi gestur umum tanpa memproses sendiri tiap peristiwa sentuhan. Hal ini dibahas lebih lanjut dalam Mendeteksi gestur.
Menangkap peristiwa sentuhan untuk satu tampilan
Sebagai alternatif untuk onTouchEvent(), Anda dapat melampirkan objek View.OnTouchListener ke objek View menggunakan metode setOnTouchListener(). Hal ini memungkinkan Anda memproses peristiwa sentuhan tanpa membuat subclass View yang ada, seperti yang ditunjukkan dalam contoh berikut:
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; } });
Berhati-hatilah dalam membuat pemroses yang menampilkan false untuk peristiwa ACTION_DOWN.
Jika Anda melakukannya, pemroses tidak akan dipanggil untuk urutan
ACTION_MOVE dan
ACTION_UP peristiwa
berikutnya. Hal ini karena ACTION_DOWN adalah titik awal untuk semua peristiwa sentuhan.
Jika Anda membuat tampilan kustom, Anda dapat mengganti
onTouchEvent(), seperti yang dijelaskan sebelumnya.
Mendeteksi gestur
Android menyediakan class GestureDetector untuk mendeteksi gestur umum. Beberapa gestur yang didukung meliputi
onDown(),
onLongPress(),
dan
onFling().
Anda dapat menggunakan GestureDetector bersama dengan metode onTouchEvent() yang dijelaskan sebelumnya.
Mendeteksi semua gestur yang didukung
Saat Anda membuat instance objek GestureDetectorCompat, salah satu parameter yang dibutuhkan adalah class yang mengimplementasikan antarmuka GestureDetector.OnGestureListener. GestureDetector.OnGestureListener memberi tahu pengguna saat terjadi peristiwa sentuhan tertentu. Agar objek GestureDetector dapat menerima peristiwa, ganti metode onTouchEvent() tampilan atau aktivitas dan teruskan semua peristiwa yang diamati ke instance detektor.
Dalam cuplikan berikut, nilai kembalian true dari setiap metode on<TouchEvent> menunjukkan bahwa peristiwa sentuhan ditangani. Nilai yang ditampilkan dari false akan meneruskan peristiwa melalui stack tampilan hingga sentuhan berhasil ditangani.
Jika menjalankan cuplikan berikut di aplikasi pengujian, Anda dapat memahami cara
tindakan dipicu saat Anda berinteraksi dengan layar sentuh dan apa
konten MotionEvent untuk setiap peristiwa sentuhan. Kemudian, Anda akan melihat
banyaknya data yang dihasilkan untuk interaksi sederhana.
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; } }
Mendeteksi subset gestur yang didukung
Jika hanya ingin memproses beberapa gestur, Anda dapat memperluas
GestureDetector.SimpleOnGestureListener
daripada mengimplementasikan antarmuka GestureDetector.OnGestureListener.
GestureDetector.SimpleOnGestureListener menyediakan implementasi untuk semua metode on<TouchEvent> dengan menampilkan false untuk semua metode tersebut. Dengan demikian, Anda hanya dapat mengganti metode yang diinginkan. Misalnya, cuplikan kode berikut membuat class yang memperluas
GestureDetector.SimpleOnGestureListener dan mengganti
onFling() serta onDown().
Baik Anda menggunakan GestureDetector.OnGestureListener maupun GestureDetector.SimpleOnGestureListener, praktik terbaiknya adalah menerapkan metode onDown() yang menampilkan true. Hal ini karena semua gestur dimulai dengan pesan onDown(). Jika Anda
menampilkan false dari onDown(), seperti
GestureDetector.SimpleOnGestureListener secara default, sistem
menganggap Anda ingin mengabaikan seluruh gestur, dan metode GestureDetector.OnGestureListener lain tidak akan dipanggil. Hal ini dapat menyebabkan masalah yang tidak terduga di aplikasi Anda. Hanya kembalikan false dari onDown() jika Anda benar-benar ingin mengabaikan seluruh gestur.
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; } } }