Di Android, ada berbagai cara untuk mencegat peristiwa dari interaksi pengguna dengan aplikasi. Saat mempertimbangkan peristiwa dalam antarmuka pengguna, pendekatannya adalah menangkap peristiwa dari objek View tertentu yang digunakan pengguna untuk berinteraksi. Class View menyediakan sarana untuk melakukannya.
Dalam berbagai class View yang akan digunakan untuk menyusun tata letak, Anda mungkin melihat beberapa metode callback
publik yang tampak berguna untuk peristiwa UI. Metode ini dipanggil oleh framework Android saat
masing-masing tindakan terjadi pada objek tersebut. Misalnya, jika View (seperti Button) disentuh,
metode onTouchEvent()
akan dipanggil pada objek tersebut. Namun, untuk mencegatnya, Anda harus memperluas
class dan mengganti metodenya. Akan tetapi, memperluas setiap objek View
untuk menangani peristiwa tersebut tidak praktis. Karena itu, class View juga berisi
sekumpulan antarmuka bertingkat dengan callback yang jauh lebih mudah ditentukan. Antarmuka ini,
yang disebut pemroses peristiwa, merupakan tiket Anda untuk menangkap interaksi pengguna dengan UI.
Walaupun Anda akan lebih sering menggunakan pemroses peristiwa untuk interaksi pengguna, mungkin ada
saatnya Anda ingin memperluas class View untuk mem-build komponen kustom.
Mungkin Anda ingin memperluas class Button
untuk membuat sesuatu yang lebih menarik. Dalam hal ini, perilaku peristiwa default untuk class Anda akan dapat ditentukan
menggunakan class pengendali peristiwa.
Pemroses peristiwa
Pemroses peristiwa merupakan antarmuka di class View
yang berisi satu
metode callback. Metode ini akan dipanggil oleh framework Android jika View tempat pemroses
didaftarkan dipicu oleh interaksi pengguna dengan item pada UI.
Metode callback berikut juga disertakan dalam antarmuka pemroses peristiwa:
onClick()
- Dari
View.OnClickListener
. Metode ini dipanggil bila pengguna menyentuh item (saat dalam mode sentuh). atau berfokus pada item dengan tombol navigasi atau trackball, lalu menekan tombol "enter" yang sesuai atau menekan trackball. onLongClick()
- Dari
View.OnLongClickListener
. Metode ini dipanggil bila pengguna menyentuh lama item (saat dalam mode sentuh), atau berfokus pada item dengan tombol navigasi atau trackball, lalu menekan dan menahan tombol "enter" yang sesuai atau menekan dan menahan trackball (selama satu detik). onFocusChange()
- Dari
View.OnFocusChangeListener
. Metode ini dipanggil bila pengguna menavigasi ke atau menjauh dari item, menggunakan tombol navigasi atau trackball. onKey()
- Dari
View.OnKeyListener
. Metode ini dipanggil bila pengguna berfokus pada item dan menekan atau melepas tombol hardware pada perangkat. onTouch()
- Dari
View.OnTouchListener
. Metode ini dipanggil bila pengguna melakukan tindakan yang digolongkan sebagai peristiwa sentuh, termasuk penekanan, pelepasan, atau gestur perpindahan pada layar (dalam batasan item). onCreateContextMenu()
- Dari
View.OnCreateContextMenuListener
. Metode ini dipanggil bila Menu Konteks sedang di-build (sebagai hasil dari "klik panjang" berkelanjutan). Lihat diskusi tentang menu konteks dalam panduan developer Menu.
Metode ini adalah satu-satunya yang menempati antarmukanya masing-masing. Untuk menentukan salah satu metode ini
dan menangani peristiwa, implementasikan antarmuka yang disarangkan dalam Activity atau tentukan sebagai class anonim.
Kemudian, teruskan satu instance implementasi
ke masing-masing metode View.set...Listener()
. (Misalnya, panggil
dan teruskan implementasi setOnClickListener()
OnClickListener
.)
Contoh di bawah menunjukkan cara mendaftarkan pemroses untuk Button.
Kotlin
protected void onCreate(savedValues: Bundle) { ... val button: Button = findViewById(R.id.corky) // Register the onClick listener with the implementation above button.setOnClickListener { view -> // do something when the button is clicked } ... }
Java
// Create an anonymous implementation of OnClickListener private OnClickListener corkyListener = new OnClickListener() { public void onClick(View v) { // do something when the button is clicked } }; protected void onCreate(Bundle savedValues) { ... // Capture our button from layout Button button = (Button)findViewById(R.id.corky); // Register the onClick listener with the implementation above button.setOnClickListener(corkyListener); ... }
Mengimplementasikan OnClickListener sebagai bagian dari Activity juga mungkin terasa lebih mudah bagi Anda. Hal ini akan menghindari beban class tambahan dan alokasi objek. Contoh:
Kotlin
class ExampleActivity : Activity(), OnClickListener { protected fun onCreate(savedValues: Bundle) { val button: Button = findViewById(R.id.corky) button.setOnClickListener(this) } // Implement the OnClickListener callback fun onClick(v: View) { // do something when the button is clicked } }
Java
public class ExampleActivity extends Activity implements OnClickListener { protected void onCreate(Bundle savedValues) { ... Button button = (Button)findViewById(R.id.corky); button.setOnClickListener(this); } // Implement the OnClickListener callback public void onClick(View v) { // do something when the button is clicked } ... }
Perlu diketahui bahwa callback onClick()
pada contoh di atas tidak
menampilkan nilai, tetapi beberapa metode pemroses peristiwa lainnya harus menampilkan boolean. Alasannya
bergantung pada peristiwa. Untuk beberapa yang menampilkan boolean, berikut alasannya:
- Ini menampilkan boolean untuk menunjukkan apakah peristiwa telah dipakai dan tidak boleh dilakukan lebih jauh. Artinya, menampilkan true untuk menunjukkan bahwa peristiwa telah ditangani dan harus berhenti di sini; menampilkan false jika Anda tidak menanganinya dan/atau peristiwa harus melanjutkan ke pemroses berbasis klik lainnya.onLongClick()
- Ini menampilkan boolean untuk menunjukkan apakah peristiwa telah dipakai dan tidak boleh dilakukan lebih jauh. Artinya, menampilkan true untuk menunjukkan bahwa peristiwa telah ditangani dan harus berhenti di sini; menampilkan false jika Anda tidak menanganinya dan/atau peristiwa harus melanjutkan ke pemroses berbasis tombol lainnya.onKey()
- Ini menampilkan boolean untuk menunjukkan apakah pemroses telah memakai peristiwa ini. Satu hal yang penting adalah peristiwa ini dapat memiliki beberapa tindakan yang saling mengikuti. Jadi, jika nilai false ditampilkan saat peristiwa tindakan ke bawah diterima, berarti Anda belum memakai peristiwa tersebut dan juga tidak tertarik dengan tindakan berikutnya dari peristiwa ini. Karena itu, Anda tidak akan dipanggil untuk tindakan lainnya dalam peristiwa, seperti gestur jari, atau peristiwa tindakan ke atas yang akan terjadi.onTouch()
Ingat bahwa peristiwa tombol hardware selalu dikirimkan ke View yang saat ini menjadi fokus. Peristiwa ini dikirim mulai dari atas
hierarki View, kemudian turun hingga mencapai tujuan yang sesuai. Jika View (atau turunan View)
saat ini memiliki fokus, maka Anda dapat melihat peristiwa berpindah melalui metode
. Sebagai alternatif untuk menangkap peristiwa tombol melalui View, Anda juga dapat menerima
semua peristiwa dalam Activity dengan dispatchKeyEvent()
dan onKeyDown()
.onKeyUp()
Selain itu, saat memikirkan tentang input teks aplikasi, ingat bahwa banyak perangkat yang hanya memiliki metode input
software. Metode tersebut tidak harus berbasis tombol; sebagian mungkin menggunakan input suara, tulisan tangan, dan sebagainya. Meskipun
menampilkan antarmuka seperti keyboard, metode input umumnya tidak memicu lini
peristiwa. Jangan pernah
mem-build UI yang mengharuskan penekanan tombol tertentu dikontrol, kecuali jika Anda ingin membatasi aplikasi hanya untuk perangkat
yang memiliki keyboard hardware. Secara khusus, jangan andalkan metode ini untuk memvalidasi input saat pengguna menekan
tombol kembali; sebagai gantinya, gunakan tindakan seperti onKeyDown()
IME_ACTION_DONE
untuk memberi tahu
metode input tentang reaksi yang diharapkan aplikasi, sehingga dapat mengubah UI-nya secara signifikan. Hindari asumsi
tentang cara metode input software seharusnya bekerja dan percayalah bahwa metode input akan menyediakan teks berformat untuk aplikasi.
Catatan: Android akan memanggil pengendali peristiwa terlebih dahulu, kemudian pengendali default yang sesuai dari definisi class. Karena itu, menampilkan true dari pemroses peristiwa ini akan menghentikan penyebaran peristiwa ke pemroses peristiwa lainnya dan juga akan memblokir callback ke pengendali peristiwa default dalam View. Pastikan bahwa Anda ingin mengakhiri peristiwa saat menampilkan true.
Pengendali peristiwa
Jika mem-build komponen kustom dari View, maka Anda akan dapat menentukan beberapa metode callback yang digunakan sebagai pengendali peristiwa default. Dalam dokumen tentang Komponen Tampilan Kustom, Anda akan mempelajari beberapa callback umum yang digunakan untuk penanganan peristiwa, termasuk:
- Dipanggil saat peristiwa tombol baru terjadi.onKeyDown(int, KeyEvent)
- Dipanggil saat peristiwa tombol ke atas terjadi.onKeyUp(int, KeyEvent)
- Dipanggil saat peristiwa gerakan trackball terjadi.onTrackballEvent(MotionEvent)
- Dipanggil saat peristiwa gerakan layar sentuh terjadi.onTouchEvent(MotionEvent)
- Dipanggil saat tampilan mendapatkan atau kehilangan fokus.onFocusChanged(boolean, int, Rect)
Ada beberapa metode lainnya yang harus Anda ketahui, yang bukan bagian dari class View, tetapi bisa berdampak langsung pada cara Anda menangani peristiwa. Jadi, saat mengelola peristiwa yang lebih kompleks dalam tata letak, pertimbangkan metode-metode lain ini:
- Metode ini memungkinkanActivity.dispatchTouchEvent(MotionEvent)
Activity
mencegat semua peristiwa sentuh sebelum dikirim ke jendela.
- Metode ini memungkinkanViewGroup.onInterceptTouchEvent(MotionEvent)
ViewGroup
memantau peristiwa saat dikirim ke View turunan.
- Panggil metode ini pada View induk untuk menunjukkan larangan mencegat peristiwa sentuh denganViewParent.requestDisallowInterceptTouchEvent(boolean)
.onInterceptTouchEvent(MotionEvent)
Mode sentuh
Saat pengguna menavigasi antarmuka pengguna dengan tombol arah atau trackball, Anda harus memberi fokus pada item yang dapat ditindaklanjuti (seperti tombol) agar pengguna dapat mengetahui apa yang akan menerima input. Namun, jika perangkat memiliki kemampuan sentuh, dan pengguna mulai berinteraksi dengan menyentuh antarmuka, maka Anda tidak perlu lagi menyorot item, atau memberi fokus pada View tertentu. Jadi, ada mode untuk interaksi yang bernama "mode sentuh".
Untuk perangkat berkemampuan sentuh, setelah pengguna menyentuh layar, perangkat
akan masuk ke mode sentuh. Dari sini dan selanjutnya, hanya View untuk
isFocusableInTouchMode()
bernilai true yang akan dapat difokuskan, seperti widget pengedit teks.
View lain yang dapat disentuh, seperti tombol, tidak akan mengambil fokus jika disentuh; View tersebut akan
langsung memicu pemroses berbasis klik ditekan.
Kapan pun pengguna menekan tombol arah atau men-scroll dengan trackball, perangkat akan keluar dari mode sentuh, dan mencari tampilan untuk difokuskan. Kini pengguna dapat melanjutkan interaksi dengan antarmuka pengguna tanpa menyentuh layar.
Status mode sentuh dipertahankan di seluruh sistem (semua jendela dan aktivitas).
Untuk mengajukan kueri terkait status saat ini, Anda dapat memanggil
isInTouchMode()
untuk mengetahui apakah perangkat sedang dalam mode sentuh.
Menangani fokus
Framework ini akan menangani gerakan fokus rutin sebagai respons input pengguna.
Ini termasuk mengubah fokus saat View dihapus atau disembunyikan, atau saat
View baru tersedia. View menunjukkan kesediaannya untuk mengambil fokus
melalui metode
. Untuk mengubah apakah View dapat
mengambil fokus, panggil isFocusable()
. Saat dalam mode sentuh,
Anda dapat mengajukan kueri apakah View memungkinkan fokus dengan setFocusable()
.
Anda dapat mengubahnya dengan isFocusableInTouchMode()
.
setFocusableInTouchMode()
Di perangkat yang menjalankan Android 9 (API level 28) atau lebih tinggi, aktivitas tidak menetapkan fokus awal. Sebagai gantinya, Anda harus meminta fokus awal secara eksplisit, jika diinginkan.
Gerakan fokus didasarkan pada algoritme yang mencari tetangga terdekat ke arah tertentu. Dalam kasus yang jarang terjadi, algoritme default mungkin tidak cocok dengan perilaku yang dimaksudkan developer. Dalam situasi ini, Anda dapat menyediakan penggantian eksplisit dengan atribut XML berikut dalam file tata letak: nextFocusDown, nextFocusLeft, nextFocusRight, dan nextFocusUp. Tambahkan salah satu atribut ini ke View dari tempat fokus menghilang. Tentukan nilai atribut untuk menjadi ID View ke tempat fokus harus diberikan. Contoh:
<LinearLayout android:orientation="vertical" ... > <Button android:id="@+id/top" android:nextFocusUp="@+id/bottom" ... /> <Button android:id="@+id/bottom" android:nextFocusDown="@+id/top" ... /> </LinearLayout>
Dalam tata letak vertikal ini, biasanya menavigasi ke atas dari Button pertama tidak akan membawa ke mana pun, juga tidak akan menavigasi ke bawah dari Button kedua. Setelah Button atas menentukan Button bawah sebagai nextFocusUp (dan sebaliknya), fokus navigasi akan beralih dari atas ke bawah dan dari bawah ke atas.
Jika Anda ingin mendeklarasikan View sebagai elemen yang dapat difokuskan dalam UI (jika biasanya bukan),
tambahkan atribut XML android:focusable
ke View dalam deklarasi tata letak.
Tetapkan nilai true. Anda juga dapat mendeklarasikan View
sebagai elemen yang dapat difokuskan saat dalam Mode Sentuh dengan android:focusableInTouchMode
.
Untuk meminta View tertentu mengambil fokus, panggil
.requestFocus()
Untuk memproses peristiwa fokus (diberi tahu bila View menerima atau kehilangan fokus), gunakan
,
sebagaimana dibahas di bagian Pemroses peristiwa.onFocusChange()