Di perangkat layar besar, pengguna sering berinteraksi dengan aplikasi menggunakan keyboard, mouse, trackpad, stilus, atau gamepad. Agar aplikasi Anda dapat menerima input dari perangkat eksternal, lakukan hal berikut:
- Uji dukungan keyboard dasar, seperti Ctrl+Z untuk mengurungkan, Ctrl+C untuk menyalin, dan Ctrl+S untuk menyimpan. Lihat Menangani tindakan keyboard untuk mengetahui daftar pintasan keyboard default.
- Menguji dukungan keyboard lanjutan, misalnya, tombol Tab dan navigasi keyboard tombol panah, konfirmasi entri teks tombol Enter, dan Spasi memutar dan menjeda di aplikasi media.
- Menguji interaksi mouse dasar, termasuk klik kanan untuk menu konteks, perubahan ikon saat mengarahkan kursor, dan peristiwa scroll roda mouse atau trackpad pada komponen kustom.
- Menguji perangkat input khusus aplikasi seperti stilus, pengontrol game, dan pengontrol MIDI aplikasi musik.
- Pertimbangkan dukungan input lanjutan yang dapat membuat aplikasi terlihat menarik di lingkungan desktop, misalnya, touchpad sebagai cross‑fader untuk aplikasi DJ, mouse capture untuk game, dan pintasan keyboard untuk pengguna yang lebih memilih keyboard.
Keyboard
Cara aplikasi Anda merespons input keyboard berkontribusi pada pengalaman pengguna layar besar. Ada tiga jenis input keyboard: navigasi, tombol, dan pintasan.
Navigasi
Navigasi keyboard jarang diterapkan di aplikasi yang berfokus pada sentuhan, tetapi pengguna mengharapkannya saat mereka menggunakan aplikasi dan menggunakan keyboard. Navigasi keyboard dapat menjadi hal penting di ponsel, tablet, perangkat foldable, dan perangkat desktop bagi pengguna dengan kebutuhan aksesibilitas.
Untuk banyak aplikasi, navigasi tombol panah dan tombol Tab ditangani
secara otomatis oleh framework Android. Misalnya, beberapa composable
dapat difokuskan secara default, seperti Button
atau composable dengan
pengubah clickable
; navigasi keyboard umumnya akan berfungsi tanpa
kode tambahan. Untuk mengaktifkan navigasi keyboard untuk composable kustom yang
tidak dapat difokuskan secara default, tambahkan pengubah focusable
:
var color by remember { mutableStateOf(Green) } Box( Modifier .background(color) .onFocusChanged { color = if (it.isFocused) Blue else Green } .focusable() ) { Text("Focusable 1") }
Untuk mengetahui informasi selengkapnya, lihat Membuat composable yang dapat difokuskan.
Saat fokus diaktifkan, framework Android akan membuat pemetaan navigasi untuk semua komponen yang dapat difokuskan berdasarkan posisinya. Hal ini biasanya berhasil seperti yang diharapkan dan tidak perlu pengembangan lebih lanjut.
Namun, Compose tidak selalu menentukan item berikutnya yang benar untuk navigasi tab untuk composable kompleks seperti tab dan daftar, misalnya, saat salah satu composable adalah composable yang dapat di-scroll secara horizontal dan tidak sepenuhnya terlihat.
Untuk mengontrol perilaku fokus, tambahkan pengubah focusGroup
ke composable
induk dari kumpulan composable. Fokus berpindah ke grup, lalu
melalui grup sebelum berpindah ke komponen berikutnya yang dapat difokuskan, misalnya:
Row {
Column(Modifier.focusGroup()) {
Button({}) { Text("Row1 Col1") }
Button({}) { Text("Row2 Col1") }
Button({}) { Text("Row3 Col1") }
}
Column(Modifier.focusGroup()) {
Button({}) { Text("Row1 Col2") }
Button({}) { Text("Row2 Col2") }
Button({}) { Text("Row3 Col2") }
}
}
Untuk mengetahui informasi selengkapnya, lihat Memberikan navigasi yang koheren dengan grup fokus.
Uji akses ke setiap elemen UI aplikasi Anda hanya menggunakan keyboard. Elemen yang sering digunakan harus dapat diakses tanpa mouse atau input sentuh.
Ingat, dukungan keyboard mungkin penting bagi pengguna dengan kebutuhan aksesibilitas.
Penekanan tombol
Untuk input teks yang akan ditangani oleh keyboard virtual di layar (IME),
seperti untuk
TextField
, aplikasi harus berperilaku seperti yang diharapkan di perangkat layar besar tanpa pekerjaan
pengembangan tambahan. Untuk penekanan tombol yang tidak dapat diperkirakan oleh framework,
aplikasi harus menangani sendiri perilaku tersebut. Hal ini terutama berlaku untuk aplikasi
dengan tampilan khusus.
Beberapa contohnya adalah aplikasi chat yang menggunakan tombol Enter untuk mengirim pesan, aplikasi media yang memulai dan menghentikan pemutaran dengan Spasi, dan game yang mengontrol gerakan dengan tombol w, a, s, dan d.
Anda dapat menangani setiap penekanan tombol dengan pengubah onKeyEvent
, yang
menerima lambda yang dipanggil saat komponen yang diubah menerima peristiwa tombol.
Properti KeyEvent#type
memungkinkan Anda menentukan apakah peristiwa tersebut adalah
penekanan tombol (KeyDown
) atau pelepasan tombol (KeyUp
):
Box(
modifier = Modifier.focusable().onKeyEvent {
if(
it.type == KeyEventType.KeyUp &&
it.key == Key.S
) {
doSomething()
true
} else {
false
}
}
) {
Text("Press S key")
}
Atau, Anda dapat mengganti callback onKeyUp()
dan menambahkan
perilaku yang diharapkan untuk setiap kode tombol yang diterima:
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { return when (keyCode) { KeyEvent.KEYCODE_ENTER -> { sendChatMessage() true } KeyEvent.KEYCODE_SPACE -> { playOrPauseMedia() true } else -> super.onKeyUp(keyCode, event) } }
Peristiwa onKeyUp
terjadi saat tombol dilepaskan. Penggunaan callback
akan mencegah aplikasi memproses beberapa peristiwa onKeyDown
jika tombol
ditahan atau dilepaskan secara perlahan. Game dan aplikasi yang perlu mendeteksi saat
tombol ditekan atau apakah pengguna menekan tombol dapat memproses
peristiwa onKeyDown
dan menangani sendiri peristiwa onKeyDown
yang berulang.
Untuk mengetahui informasi selengkapnya, lihat Menangani tindakan keyboard.
Pintasan
Pintasan keyboard umum yang mencakup tombol Ctrl, Alt, Shift, dan Meta diharapkan saat menggunakan keyboard hardware. Jika aplikasi tidak menerapkan pintasan, pengalaman tersebut dapat membuat pengguna merasa kesulitan. Pengguna lanjutan juga menghargai adanya pintasan untuk tugas khusus aplikasi yang sering digunakan. Pintasan membuat aplikasi lebih mudah digunakan dan membedakan aplikasi dari aplikasi yang tidak memiliki pintasan.
Beberapa pintasan umum antara lain Ctrl+S (simpan), Ctrl+Z (urungkan), dan Ctrl+Shift+Z (ulangi). Untuk mengetahui daftar pintasan default, lihat Menangani tindakan keyboard.
Objek KeyEvent
memiliki atribut berikut yang menunjukkan apakah
tombol pengubah ditekan:
Contoh:
Box(
Modifier.onKeyEvent {
if (it.isAltPressed && it.key == Key.A) {
println("Alt + A is pressed")
true
} else {
false
}
}
.focusable()
)
Untuk informasi selengkapnya, lihat referensi berikut:
Stilus
Banyak perangkat layar besar dilengkapi dengan stilus. Aplikasi Android menangani stilus sebagai input layar sentuh. Beberapa perangkat mungkin juga memiliki tablet menggambar USB atau Bluetooth, seperti Wacom Intuos. Aplikasi Android dapat menerima input bluetooth, tetapi tidak dapat menerima input USB.
Untuk mengakses objek stilus MotionEvent
, tambahkan pengubah pointerInteropFilter
ke permukaan gambar. Terapkan class ViewModel
dengan metode yang
memproses peristiwa gerakan; teruskan metode sebagai lambda onTouchEvent
dari
pengubah pointerInteropFilter
:
@Composable
@OptIn(ExperimentalComposeUiApi::class)
fun DrawArea(modifier: Modifier = Modifier) {
Canvas(modifier = modifier
.clipToBounds()
.pointerInteropFilter {
viewModel.processMotionEvent(it)
}
) {
// Drawing code here.
}
}
Objek MotionEvent
berisi informasi tentang peristiwa:
MotionEvent#getToolType()
menampilkanTOOL_TYPE_FINGER
,TOOL_TYPE_STYLUS
, atauTOOL_TYPE_ERASER
bergantung pada alat yang membuat kontak dengan layarMotionEvent#getPressure()
melaporkan tekanan fisik yang diterapkan pada pena stilus (jika didukung)MotionEvent#getAxisValue()
denganMotionEvent.AXIS_TILT
danMotionEvent.AXIS_ORIENTATION
memberikan kemiringan dan orientasi fisik stilus (jika didukung)
Titik historis
Android mengumpulkan input peristiwa dan mengirimkannya sekali per frame. Stilus dapat
melaporkan peristiwa pada frekuensi yang jauh lebih tinggi daripada tampilan. Saat membuat aplikasi
menggambar, periksa peristiwa yang mungkin terjadi di masa lalu menggunakan
API getHistorical
:
MotionEvent#getHistoricalX()
MotionEvent#getHistoricalY()
MotionEvent#getHistoricalPressure()
MotionEvent#getHistoricalAxisValue()
Penolakan telapak tangan
Saat menggambar, menulis, atau berinteraksi dengan aplikasi Anda menggunakan stilus, terkadang pengguna
menyentuh layar dengan telapak tangan mereka. Peristiwa sentuh (disetel ke
ACTION_DOWN
atau ACTION_POINTER_DOWN
) dapat dilaporkan ke aplikasi Anda
sebelum sistem mengenali dan mengabaikan sentuhan telapak tangan yang tidak disengaja.
Android membatalkan peristiwa sentuhan telapak tangan dengan mengirim MotionEvent
. Jika
aplikasi Anda menerima ACTION_CANCEL
, batalkan gestur. Jika aplikasi Anda menerima
ACTION_POINTER_UP
, periksa apakah FLAG_CANCELED
telah disetel. Jika ya, batalkan
gestur.
Jangan hanya memeriksa FLAG_CANCELED
. Di Android 13 (API level 33) dan yang lebih baru,
sistem menyetel FLAG_CANCELED
untuk peristiwa ACTION_CANCEL
, tetapi sistem
tidak menyetel tanda pada versi Android yang lebih rendah.
Android 12
Di Android 12 (API level 32) dan yang lebih rendah, deteksi penolakan telapak tangan hanya
dapat dilakukan untuk peristiwa sentuh satu pointer. Jika sentuhan telapak tangan adalah satu-satunya pointer,
sistem akan membatalkan peristiwa dengan menyetel ACTION_CANCEL
pada objek peristiwa
gerakan. Jika pointer lain turun, sistem akan menyetel ACTION_POINTER_UP
, yang
tidak cukup untuk mendeteksi penolakan telapak tangan.
Android 13
Di Android 13 (API level 33) dan yang lebih baru, jika sentuhan telapak tangan adalah satu-satunya pointer,
sistem akan membatalkan peristiwa dengan menyetel ACTION_CANCEL
dan FLAG_CANCELED
pada
objek peristiwa gerakan. Jika pointer lain turun, sistem akan menyetel
ACTION_POINTER_UP
dan FLAG_CANCELED
.
Setiap kali aplikasi Anda menerima peristiwa gerakan dengan ACTION_POINTER_UP
, periksa
FLAG_CANCELED
untuk menentukan apakah peristiwa tersebut menunjukkan penolakan telapak tangan (atau
pembatalan peristiwa lainnya).
Aplikasi pencatatan
ChromeOS memiliki intent khusus yang menampilkan aplikasi pencatatan terdaftar kepada pengguna. Untuk mendaftarkan aplikasi sebagai aplikasi pencatatan, tambahkan kode berikut ke manifes aplikasi Anda:
<intent-filter>
<action android:name="org.chromium.arc.intent.action.CREATE_NOTE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Saat aplikasi didaftarkan ke sistem, pengguna dapat memilihnya sebagai aplikasi
pencatatan default. Saat catatan baru diminta, aplikasi harus membuat
catatan kosong yang siap untuk input stilus. Saat pengguna ingin memberi anotasi pada gambar
(seperti screenshot atau gambar yang didownload), aplikasi akan diluncurkan dengan ClipData
yang berisi satu atau beberapa item dengan URI content://
. Aplikasi harus membuat
catatan yang menggunakan gambar terlampir pertama sebagai gambar latar dan dalam mode
yang memungkinkan pengguna menggambar dengan stilus.
Menguji intent pencatatan tanpa stilus
[TBD remove section.]
Untuk menguji apakah aplikasi merespons intent pencatatan dengan benar tanpa stilus aktif, gunakan metode berikut untuk menampilkan opsi pencatatan di ChromeOS:
- Alihkan ke mode developer dan buat perangkat agar dapat ditulis
- Tekan Ctrl+Alt+F2 untuk membuka terminal
- Jalankan perintah
sudo vi /etc/chrome_dev.conf
- Tekan
i
untuk mengedit dan menambahkan--ash-enable-palette
ke baris baru di akhir file - Simpan dengan menekan Esc, lalu mengetikkan :, w, q, dan menekan Enter
- Tekan Ctrl+Alt+F1 untuk kembali ke UI ChromeOS reguler
- Logout, lalu login kembali
Sekarang, menu stilus akan ada di rak:
- Ketuk tombol stilus di rak, lalu pilih Catatan baru. Ini akan membuka catatan gambar kosong.
- Ambil screenshot. Dari rak, pilih tombol stilus > Tangkap layar atau download gambar. Akan ada opsi untuk Anotasi gambar dalam notifikasi. Tindakan ini akan meluncurkan aplikasi dengan gambar yang siap untuk dianotasi.
Dukungan mouse dan touchpad
Umumnya aplikasi hanya perlu menangani tiga peristiwa besar yang berfokus pada layar: klik kanan, arahkan kursor, dan tarik lalu lepas.
Klik kanan
Tindakan apa pun yang menyebabkan aplikasi menampilkan menu konteks, seperti menyentuh lama pada item daftar, juga harus menanggapi peristiwa klik kanan.
Untuk menangani peristiwa klik kanan, aplikasi harus mendaftarkan
View.OnContextClickListener
:
Box(modifier = Modifier.fillMaxSize()) {
AndroidView(
modifier = Modifier.fillMaxSize(),
factory = { context ->
val rootView = FrameLayout(context)
val onContextClickListener =
View.OnContextClickListener { view ->
showContextMenu()
true
}
rootView.setOnContextClickListener(onContextClickListener)
rootView
},
)
}
Untuk mengetahui detail tentang membuat menu konteks, lihat Membuat menu kontekstual.
Arahkan kursor
Anda dapat membuat tata letak aplikasi terasa keren dan lebih mudah digunakan dengan menangani peristiwa pengarahan kursor. Hal ini terutama berlaku untuk komponen kustom:
Dua contoh yang paling umum adalah:
- Menunjukkan kepada pengguna apakah suatu elemen memiliki perilaku interaktif atau tidak, seperti dapat diklik atau dapat diedit, dengan mengubah ikon kursor mouse
- Menambahkan masukan visual ke item dalam daftar atau petak besar jika kursor diarahkan ke atasnya
Tarik lalu lepas
Dalam lingkungan multi-aplikasi, pengguna berharap dapat menarik lalu melepas item di antara aplikasi. Hal ini berlaku untuk perangkat desktop serta tablet, ponsel, dan perangkat foldable dalam mode layar terpisah.
Pertimbangkan apakah pengguna cenderung akan menarik item ke aplikasi Anda. Misalnya, editor foto akan menerima foto, pemutar audio akan menerima file audio, dan program menggambar akan menerima foto.
Untuk menambahkan dukungan tarik lalu lepas, lihat Tarik lalu lepas , dan lihat postingan blog Android di ChromeOS — Mengimplementasikan Tarik & Lepas.
Pertimbangan khusus untuk ChromeOS
- Jangan lupa untuk meminta izin dengan
requestDragAndDropPermissions()
untuk mengakses item yang ditarik dari luar aplikasi Item harus memiliki flag
View.DRAG_FLAG_GLOBAL
agar dapat ditarik ke aplikasi lainLihat Memulai peristiwa tarik
Dukungan pointer lanjutan
Aplikasi yang menangani input mouse dan touchpad tingkat lanjut harus menerapkan
pengubah
pointerInput
untuk mendapatkan PointerEvent
:
@Composable private fun LogPointerEvents(filter: PointerEventType? = null) { var log by remember { mutableStateOf("") } Column { Text(log) Box( Modifier .size(100.dp) .background(Color.Red) .pointerInput(filter) { awaitPointerEventScope { while (true) { val event = awaitPointerEvent() // handle pointer event if (filter == null || event.type == filter) { log = "${event.type}, ${event.changes.first().position}" } } } } ) } }
Periksa objek PointerEvent
untuk menentukan hal berikut:
PointerType
: Mouse, stilus, sentuh, dan sebagainya dariPointerEvent#changes
PointerEventType
: Tindakan pointer, seperti tekan, gerakkan, scroll, dan lepaskan
Pengontrol game
Beberapa perangkat Android layar besar mendukung hingga empat pengontrol game. Gunakan API pengontrol game Android standar untuk menangani pengontrol game (lihat Mendukung pengontrol game).
Tombol pengontrol game dipetakan ke nilai umum setelah pemetaan umum. Namun, tidak semua produsen pengontrol game mengikuti konvensi pemetaan yang sama. Anda dapat memberikan pengalaman yang jauh lebih baik jika mengizinkan pengguna memilih berbagai pemetaan pengontrol yang populer. Lihat Memproses penekanan tombol gamepad untuk mengetahui informasi selengkapnya.
Mode terjemahan input
ChromeOS mengaktifkan mode terjemahan input secara default. Untuk sebagian besar aplikasi Android, mode ini membantu aplikasi bekerja seperti yang diharapkan di lingkungan desktop. Beberapa contoh termasuk mengaktifkan scrolling dua jari secara otomatis pada touchpad, scrolling roda mouse, dan memetakan koordinat tampilan mentah ke koordinat jendela. Umumnya, developer aplikasi tidak perlu menerapkan perilaku ini sendiri.
Jika aplikasi menerapkan perilaku input kustom, misalnya menentukan tindakan cubit touchpad dengan dua jari kustom, atau terjemahan input ini tidak memberikan peristiwa input yang diharapkan oleh aplikasi, Anda dapat menonaktifkan mode terjemahan input dengan menambahkan tag berikut ke manifes Android:
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />