"Gestur sentuh" terjadi ketika pengguna meletakkan satu jari atau lebih pada layar sentuh, dan aplikasi Anda akan mengartikan pola sentuhan tersebut sebagai gestur tertentu. Ada dua fase yang sesuai untuk deteksi gestur:
- Mengumpulkan data tentang peristiwa sentuh.
- Menginterpretasikan data untuk melihat apakah telah memenuhi kriteria untuk salah satu gestur yang didukung aplikasi Anda.
Lihat referensi terkait berikut:
Class support library
Contoh dalam tutorial ini menggunakan class GestureDetectorCompat
dan MotionEventCompat
. Class ini berada di Support Library. Anda harus menggunakan class Support Library jika memungkinkan untuk memberikan kompatibilitas dengan perangkat yang menjalankan Android 1.6 dan versi yang lebih tinggi. Perhatikan bahwa MotionEventCompat
bukan pengganti class MotionEvent
. Class ini menyediakan metode utilitas statis untuk meneruskan objek MotionEvent
Anda untuk menerima tindakan yang diinginkan 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 tiap urutan peristiwa sentuhan (posisi, tekanan, ukuran, tambahan jari lain, dll.)
yang akhirnya diidentifikasi sebagai gestur, onTouchEvent()
akan aktif beberapa kali.
Gestur tersebut dimulai ketika pengguna pertama kali menyentuh layar, terus berlanjut ketika sistem melacak posisi jari pengguna, dan berakhir dengan menangkap peristiwa terakhir saat jari pengguna meninggalkan layar. Melalui 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 dalam Aktivitas atau Tampilan, ganti callback onTouchEvent()
.
Cuplikan berikut menggunakan getActionMasked()
untuk mengekstrak tindakan yang dilakukan pengguna dari parameter event
. Hal ini akan memberi data mentah yang Anda butuhkan untuk menentukan apakah gestur yang terkait dengan Anda terjadi:
Kotlin
class MainActivity : Activity() { ... // This example shows an Activity, but you would use the same approach if // you were subclassing a View. override fun onTouchEvent(event: MotionEvent): Boolean { val action: Int = MotionEventCompat.getActionMasked(event) return when (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, but you would use the same approach if // you were subclassing a View. @Override public boolean onTouchEvent(MotionEvent event){ int action = MotionEventCompat.getActionMasked(event); switch(action) { 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); } }
Selanjutnya, Anda dapat melakukan pemrosesan sendiri terhadap peristiwa ini untuk menentukan apakah telah terjadi gestur. Ini adalah jenis pemrosesan yang harus Anda lakukan untuk gestur kustom. Namun, jika aplikasi Anda menggunakan gestur umum seperti ketuk dua kali, tekan lama, lempar, dan sebagainya, Anda dapat memanfaatkan class GestureDetector
. GestureDetector
memudahkan Anda mendeteksi gestur umum tanpa memproses sendiri tiap peristiwa sentuhan. Hal ini akan dibahas di bawah dalam Mendeteksi Gestur.
Menangkap peristiwa sentuhan untuk satu tampilan
Sebagai ganti onTouchEvent()
, Anda dapat menyertakan objek View.OnTouchListener
ke setiap objek View
menggunakan metode setOnTouchListener()
. Hal ini memungkinkan Anda memproses peristiwa sentuhan tanpa membuat subclass View
yang ada. Contoh:
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 string peristiwa ACTION_MOVE
dan ACTION_UP
berikutnya. Ini terjadi karena ACTION_DOWN
adalah titik awal untuk semua peristiwa sentuhan.
Jika Anda membuat Tampilan kustom, Anda dapat mengganti onTouchEvent()
, seperti yang dijelaskan di atas.
Mendeteksi gestur
Android menyediakan class GestureDetector
untuk mendeteksi gestur umum. Beberapa gestur yang didukung meliputi onDown()
, onLongPress()
, onFling()
, dan sebagainya. Anda dapat menggunakan GestureDetector
bersama dengan metode onTouchEvent()
yang dijelaskan di atas.
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, Anda dapat mengganti metode onTouchEvent()
Tampilan atau Aktivitas, dan meneruskan semua peristiwa yang diamati ke instance detektor.
Dalam cuplikan berikut, nilai kembalian true
dari setiap metode on<TouchEvent>
menunjukkan bahwa Anda telah menangani peristiwa sentuhan. Nilai yang ditampilkan dari false
akan meneruskan peristiwa melalui stack tampilan hingga sentuhan berhasil ditangani.
Jalankan cuplikan berikut untuk melihat bagaimana tindakan dipicu saat Anda berinteraksi dengan layar sentuh, dan apa konten MotionEvent
untuk setiap peristiwa sentuhan. Anda akan menyadari banyaknya data yang dihasilkan, bahkan 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
, bukan implementasi 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 di bawah membuat class yang memperluas GestureDetector.SimpleOnGestureListener
dan mengganti onFling()
serta onDown()
.
Terlepas dari apakah Anda menggunakan GestureDetector.OnGestureListener
atau tidak, praktik terbaiknya adalah mengimplementasikan metode onDown()
yang menampilkan true
. Ini disebabkan karena semua gestur dimulai dengan pesan onDown()
. Jika Anda mengembalikan false
dari onDown()
, seperti GestureDetector.SimpleOnGestureListener
secara default, sistem akan menganggap bahwa Anda ingin mengabaikan seluruh gestur, dan metode GestureDetector.OnGestureListener
lain tidak akan pernah dipanggil.
Hal ini berpotensi menyebabkan masalah yang tidak terduga di aplikasi Anda. Satu-satunya waktu untuk mengembalikan false
dari onDown()
adalah 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){ this.mDetector.onTouchEvent(event); 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; } } }