Seiring berkembangnya faktor bentuk baru di luar layar sentuh, sistem input Compose telah berevolusi untuk memenuhi tantangan tersebut. Arsitektur berlapisnya memberikan fondasi untuk mendukung semuanya, mulai dari gestur trackpad lanjutan hingga input hardware baru dengan lancar.
Melalui perincian arsitektur yang jelas dan contoh kode langsung, ikuti siklus proses peristiwa input mulai dari lapisan platform OS hingga detektor gestur dan komponen UI Compose. Anda akan menemukan cara melacak peristiwa di seluruh stack, menerapkan pola arsitektur utama untuk jenis input yang muncul, dan men-debug interaksi gestur yang kompleks dengan percaya diri di aplikasi Anda sendiri.
performTrackpadInput. API ini menyediakan platform pengujian yang sudah dikenal untuk memvalidasi bahwa aplikasi menangani perangkat non-sentuh dengan benar.Transkrip
Halo, semuanya!
Semoga Anda menikmati Android Developer Summit, dan terima kasih telah menghadiri diskusi kami.
Saya Alex Vanyo, software engineer di tim Compose, dan saya ditemani oleh Jeremy, yang juga software engineer di tim Compose.
Kami berdua telah berupaya meningkatkan sistem input Jetpack Compose, dan hari ini, kami akan membahas cara kami menskalakannya di luar layar sentuh untuk mempermudah dukungan input non-sentuh secara langsung.
Input, secara umum, mencakup cara apa pun yang digunakan pengguna untuk berinteraksi dengan aplikasi Anda.
Layar sentuh mungkin adalah hal pertama yang Anda pikirkan untuk aplikasi seluler, tetapi tentu saja bukan satu-satunya jenis input.
Jenis input lainnya mencakup keyboard fisik, mouse, trackpad, stilus, pengontrol, dan perangkat putar.
Kami juga melihat jenis input baru, seperti trackpad pada kacamata AI, pelacakan mata dan tangan di XR, serta gestur jari dan pergelangan tangan di Wear.
Dan jika Anda ingin lebih umum, ada juga jenis input lain: hal-hal seperti IME software untuk pengeditan teks, mikrofon, kamera, dan sensor perangkat lainnya.
Anda harus memperkirakan bahwa aplikasi Anda akan digunakan dengan berbagai jenis input.
Salah satu alasannya adalah makin beragamnya perangkat yang menjalankan aplikasi, dan makin meningkatnya kemampuan adaptasi perangkat tersebut.
Faktor bentuk perangkat mungkin memiliki metode input yang paling umum, tetapi penting untuk tidak berasumsi bahwa faktor bentuk perangkat tertentu menyiratkan penggunaan jenis input tertentu.
Meskipun Chromebook memiliki trackpad dan keyboard bawaan, hal itu tidak membuat jenis input tersebut unik untuk faktor bentuk tersebut.
Anda harus memperkirakan bahwa keyboard fisik, trackpad, dan mouse juga akan digunakan di ponsel, tablet, dan TV, dan beberapa TV bahkan memiliki layar sentuh.
Alasan besar kedua untuk mengantisipasi dan mendukung beberapa jenis input adalah aksesibilitas.
Mengizinkan pengguna menggunakan perangkat input pilihan mereka dan mengizinkan mereka beralih perangkat input sesuai keinginan adalah hal yang tepat untuk membuat aplikasi lebih mudah diakses dan digunakan.
Dan bergantung pada wilayah hukum, mungkin ada persyaratan hukum untuk memiliki perilaku tertentu yang kompatibel di aplikasi Anda untuk jenis input ini, terutama terkait hal-hal seperti keyboard dan mouse.
Singkatnya, Anda harus membangun dukungan untuk berbagai jenis input, terlepas dari faktor bentuknya.
Jadi, mari kita lihat cara Jetpack Compose membantu aplikasi Anda memenuhi kebutuhan pengguna ini.
Filosofi Compose, secara umum, adalah bahwa berbagai jenis input ini harus berperilaku sebagaimana mestinya dengan komponen standar tanpa Anda perlu melakukan hal khusus.
Kemudian, Anda akan memiliki alat yang diperlukan untuk menyesuaikan dan mengubah perilaku sesuai keinginan Anda.
Jadi, selain jenis input awal tersebut, seiring makin banyaknya jenis input yang didukung oleh platform yang mendasarinya, kami berupaya membangun dukungan untuk jenis input tersebut ke dalam komponen Compose, sehingga meningkatkan perilaku aplikasi Anda hanya dengan mengupdate versi Compose.
Kita akan melihat dua contoh tersebut dalam pembahasan ini, keduanya merupakan tambahan terbaru untuk Compose.
Secara kebetulan, keduanya adalah perangkat seperti trackpad, tetapi seperti yang akan Anda lihat, keduanya digunakan dengan cara yang sangat berbeda.
Jadi, mari kita mulai dengan beberapa pekerjaan terbaru pada trackpad jenis gaya laptop.
Trackpad adalah perangkat input berbasis pointer.
Lebih khusus lagi, saat menggunakan trackpad, Anda akan mendapatkan koordinat dua dimensi.
Namun, tidak seperti layar sentuh, koordinat jari di trackpad tidak berada langsung di ruang koordinat UI Anda.
Sebagai gantinya, untuk trackpad seperti laptop, ada terjemahan untuk mengontrol kursor.
Dalam penerjemahan ini, Anda dapat mengharapkan banyak konversi platform yang rumit: hal-hal seperti akselerasi kursor dan penolakan telapak tangan.
Jadi, yang Anda dapatkan di sisi Compose adalah pointer yang sesuai dengan lokasi kursor yang biasanya berfungsi seperti input mouse.
Dari platform Android, kita mendapatkan informasi pengarahan kursor, klik termasuk klik sekunder atau tersier, dan semua informasi ini digabungkan ke dalam MotionEvent.
Untuk memahami cara kami meningkatkan perilaku di versi terbaru Compose, mari kita lihat ringkasan umum tentang cara Compose menangani peristiwa pointer ini dengan lebih cermat.
Saya akan membaginya menjadi enam fase yang berbeda, dan kita akan membahas semuanya satu per satu.
Fase pertama adalah MotionEvents yang berpindah ke Compose.
Jadi, di balik layar, Compose sebenarnya hanyalah sebuah tampilan: tampilan yang sangat rumit dan melakukan banyak hal, tetapi tetap saja hanyalah sebuah tampilan, yang berarti harus berfungsi dalam keseluruhan sistem Android untuk input pointer.
Jadi, di Compose, itu berarti Compose, karena berada di dalam jendela normal di dalam aktivitas normal, akan mendapatkan MotionEvent: MotionEvent platform Android.
Kemudian, Compose perlu menanganinya dan melakukan semua yang ingin Anda lakukan dalam Compose terkait input pointer.
Fase pertama di sini adalah menerjemahkan MotionEvent tersebut menjadi representasi internal yang tidak bergantung pada platform di Compose, yang kami sebut PointerInputEvent.
Jenis ini adalah jenis internal, jadi Anda tidak akan melihatnya secara langsung.
Dan jika Anda ingin melihat semua detail tentang apa yang terjadi di sini, Anda dapat melihat MotionEventAdapter, tetapi kita akan melewati detail tersebut di sini.
Jadi, sekarang kita memiliki representasi MotionEvent yang tidak bergantung pada platform di Compose.
Selanjutnya, ternyata input biasanya terjadi seiring waktu.
Anda mendapatkan banyak peristiwa input satu demi satu, jadi sangat berguna untuk mengetahui apa yang terjadi dari waktu ke waktu.
Hal-hal seperti gestur, pelacakan kecepatan, deteksi slop, semuanya perlu memahami apa yang terjadi pada setiap titik waktu.
Jadi, tahap berikutnya dalam pipeline pemrosesan ini adalah menambahkan informasi waktu ini, dan akan melakukan beberapa pra-pemrosesan berdasarkan peristiwa pointer berturut-turut.
Dalam kode, Anda dapat melihatnya sebagai mengambil PointerInputEvent saat ini, menggabungkannya dengan apa yang terjadi pada peristiwa sebelumnya, lalu kita membuat InternalPointerEvent yang peka waktu.
Ini adalah jenis internal lain, seperti yang mungkin ditunjukkan oleh namanya, tetapi Anda dapat menganggapnya sebagai peta ID pointer yang berbeda untuk perubahan input pointer, dan PointerInputChanges adalah jenis publik.
Itu yang pertama.
Dan sesuatu yang mungkin Anda perhatikan saat memikirkan berbagai ID pointer adalah sekarang setelah kita mengetahui pelacakan waktu, kita juga dapat melacak kapan ID pointer muncul dan hilang.
Tidak hanya satu.
Jika Anda menggunakan beberapa jari pada layar sentuh, Anda mungkin memiliki beberapa pointer yang muncul dan hilang secara bersamaan, dan kita perlu menanganinya.
Sekali lagi, jika ingin mempelajari detailnya, Anda dapat melihat PointerInputChangeEventProducer, yang melakukan semua ini, tetapi kita akan melewatinya.
Masih banyak hal yang harus kita bahas.
Jadi, sekarang kita memiliki representasi input Compose, dan memiliki informasi waktu.
Langkah berikutnya adalah mencari tahu apa yang harus dilakukan dengan peristiwa tersebut.
Ke mana kami harus mengirimkannya?
Hal ini mengarah pada pengujian Jalur Hit.
Jadi, bayangkan situasi saat kita memiliki MotionEvent yang dikirim, dan ComposeView ini mengisi seluruh jendela, mungkin seluruh layar.
Kita perlu mencari tahu ke mana harus mengirimkannya.
Dan karena Compose hanyalah sebuah tampilan, tetapi kita memiliki banyak hal di dalam Compose, banyak node, tombol, hal-hal yang berinteraksi dengan Anda, kita perlu melakukan semua pekerjaan di Compose untuk mencari tahu ke mana harus mengirim peristiwa yang terjadi di posisi tertentu, dan mencari tahu node mana yang benar-benar tertarik dengannya.
Node tata letak ini memiliki koordinat, batas, dan bentuk, jadi kita perlu mencari tahu mana yang terkena, jika ada.
Namun, itu juga bukan tampilan yang paling umum.
Ternyata kita suka menempatkan elemen interaktif di dalam elemen interaktif lainnya, misalnya, menempatkan tombol di dalam daftar.
Ternyata kita sering melakukannya.
Jadi, kasus umum lengkapnya di sini adalah peristiwa input tertentu membuat Jalur Hit lengkap yang melewati setiap node yang dapat berinteraksi yang terkena koordinat peristiwa input.
Jadi, dalam hal ini, ada tiga elemen yang dilalui dalam hierarki bertingkat.
Jadi, kita memiliki Jalur Klik, tetapi itu pun tidak cukup.
Ingat bahwa kita memiliki beberapa peristiwa input pointer, beberapa pointer yang mungkin ditekan?
Kita sebenarnya perlu memiliki Hierarki Jalur Klik yang lengkap.
Tidak hanya ada satu Jalur Klik jika Anda memiliki beberapa pointer.
Jadi, itulah fase berikutnya, yaitu membuat dan memperbarui Hit Path Tree ini.
Jadi, ini adalah gambaran yang lebih mendetail tentang apa yang terjadi.
Di sebelah kiri, kita memiliki node yang ditata secara visual, lalu di kiri bawah, Anda dapat melihat representasi hierarkis, node mana yang berada di dalam node lain, mana yang merupakan ancestor atau turunan satu sama lain.
Saat pointer turun, kita melacak Jalur Hit tersebut, jalur lengkap melalui hierarki, lalu kita mendapatkan Jalur Hit untuk pointer tertentu tersebut.
Jalur Klik ini kemudian menjadi hierarki saat kita mendapatkan pointer kedua.
Jalur ini mungkin bersinggungan dengan beberapa node yang sama dengan jalur lainnya, tetapi mungkin juga berinteraksi dengan node lain.
Jadi, di sebelah kanan, itulah Hit Path Tree yang sekarang kami kelola.
Dan pointer dapat muncul dan hilang, jadi kita perlu mempertahankan ini dari waktu ke waktu untuk memastikan bahwa kita mendapatkan daftar lengkap node yang tertarik dengan setiap peristiwa yang sedang berlangsung saat ini.
Oke.
Jadi, sekarang kita memiliki Hit Path Tree yang kita pertahankan untuk peristiwa input ini, yang berarti kita akan beralih ke fase berikutnya.
Sekarang, kita tahu ke mana kita akan mengirimkan peristiwa input pointer ini, node mana yang tertarik pada setiap peristiwa tertentu.
Setelah mengetahuinya, kita dapat melakukan transformasi koordinat.
Ternyata akan sangat bagus jika node Anda mendapatkan peristiwa input dalam ruang koordinat lokalnya sendiri, sehingga Anda tidak perlu melakukan banyak, Anda tahu, matematika koordinat sendiri.
Jadi, setelah mengetahuinya, kita dapat mengambil peristiwa input pointer, menggabungkannya dengan koordinat node yang diinginkan, lalu ini akan membuat PointerEvent publik yang akan dikirimkan kepada Anda semua dan pengubah input pointer.
Dan itulah hal terakhir dalam fase kita, fase 6, yang akhirnya benar-benar mengirimkan acara.
Ini adalah peristiwa input pointer yang telah terjadi, dan dikirim ke node untuk melakukan apa pun yang diinginkan.
Kami melakukannya dalam tiga tahap yang berbeda.
Kita memiliki tahap awal, tahap utama, dan tahap akhir.
Alasan memiliki tiga penerusan yang berbeda adalah agar node dapat berkomunikasi satu sama lain dan mengomunikasikan minat pada bagian tertentu dari peristiwa input pointer tertentu, lalu menggunakan bagian yang berbeda sebagai bagian dari pengiriman.
Jadi, penerusan pertama, penerusan awal, beralih dari ancestor ke turunan.
Contoh kegunaannya adalah jika beberapa node tata letak luar mungkin merupakan penampung scroll, dan node tersebut tahu bahwa scroll telah dimulai, dan ingin menghentikan semua peristiwa pointer agar tidak menjangkau turunannya.
Hal ini, pada penerusan awal, memungkinkannya untuk menggunakannya, dan kemudian turunan tidak akan mendapatkan peristiwa lagi.
Pass kedua adalah pass utama.
Dan ini satu-satunya yang beralih dari turunan ke ancestor.
Seperti namanya, ini adalah penerusan utama untuk melakukan berbagai hal.
Misalnya, di sinilah turunan akan menggunakan peristiwa tekan, memulai penanganan klik, lalu mendapatkan kesempatan untuk melakukannya sebelum induknya jika Anda memiliki elemen bertingkat yang dapat diklik.
Lalu, tahap terakhir, tahap final, terlihat sama seperti tahap awal, yang beralih dari ancestor ke turunan.
Di sinilah turunan dapat memberi tahu induk bahwa induk menggunakan bagian dari peristiwa.
Jadi, dan mungkin jika turunan mulai menangani klik, tetapi kemudian induk mulai men-scroll, turunan dapat melihat bahwa induk melakukannya, lalu turunan dapat membatalkan klik yang mulai ditanganinya.
Jadi, itulah tiga tahap dan enam fase.
Ini adalah fondasi untuk semua hal di atas sistem input pointer.
Semua penanganan gestur, scrollable, draggable, clickable, dan input pointer kustom Anda dibuat di atas fondasi ini.
Jadi, dengan semua itu, sekarang kita dapat membahas sedikit tentang detail cara kami meningkatkan dukungan perilaku trackpad di Compose.
Jadi, sebelum Compose 1.12, peristiwa input trackpad akan dilaporkan sebagai jenis sentuhan pointer, karena jari berinteraksi secara fisik dengan trackpad untuk mengontrol kursor.
Namun, ekspektasi pengguna adalah jenis input ini berfungsi lebih seperti mouse fisik.
Jadi, kami mengubah jenis pointer dari PointerType.Touch menjadi PointerType.Mouse.
Dengan perubahan ini, pengguna akan melihat pengalaman mouse dan trackpad yang jauh lebih konsisten untuk komponen apa pun yang melihat informasi ini.
Contohnya adalah perilaku tooltip: Anda mungkin menginginkan perilaku yang sama untuk trackpad dan mouse untuk tooltip.
Perubahan besar kedua yang kami buat terkait trackpad berkaitan dengan gestur multi-jari yang akan Anda lakukan di trackpad.
Sebelumnya, Compose menggunakan konsep jari palsu yang cerdas, tetapi agak aneh, dari platform Android.
Mari kita lihat artinya.
Saat Anda menggunakan dua jari pada trackpad untuk menggeser, Android akan menghasilkan satu jari layar sentuh palsu yang turun di tempat kursor berada.
Kemudian, saat Anda menggerakkan jari di trackpad, jari palsu di layar sentuh akan bergerak dengan jarak dan arah yang tepat untuk meniru perilaku yang diinginkan, lalu dilepaskan.
Jadi, dua jari yang bergerak ke atas di trackpad diterjemahkan menjadi satu jari palsu di layar sentuh, yang juga bergerak ke atas, yang pada gilirannya menyebabkan scroll ke bawah.
Hal yang menarik di sini adalah jika Anda, seperti saya, menggunakan fitur scroll trackpad terbalik, Anda ingin scroll benar-benar berjalan ke arah yang berlawanan.
Hal ini dicapai dengan membalik arah gerakan jari palsu.
Jadi sekarang, dua jari di trackpad yang bergerak ke atas diterjemahkan menjadi satu jari palsu di layar sentuh yang bergerak ke bawah, yang pada gilirannya menyebabkan scroll ke atas, kebalikan dari yang kita miliki sebelumnya.
Penskalaan bekerja dengan cara yang serupa.
Saat Anda menggunakan dua jari di trackpad untuk menskalakan, Android akan menghasilkan dua jari layar sentuh palsu yang turun, lalu bergerak lebih dekat atau lebih jauh, bergantung pada gestur, untuk meniru perilaku yang diinginkan, yaitu memperbesar atau memperkecil.
Jadi, sejak Compose 1.12 untuk menggeser dan Compose 1.13 untuk menskalakan, kami kini mengintersepsi jari palsu tersebut.
Kita tidak mengirimkannya seperti yang diberikan platform kepada kita, dan kita menafsirkannya kembali menjadi jenis peristiwa pointer baru: PanStart, PanMove, dan PanEnd untuk menggeser, serta ScaleStart, ScaleChange, dan ScaleEnd untuk menskalakan.
Dan kita melakukannya dalam fase konversi peristiwa Android ke Compose yang telah saya bahas sebelumnya.
Jadi, kami mengonversi peristiwa Jari Palsu ke jenis yang sesuai, lalu mengirimkan gestur yang ditentukan platform ini ke Jalur Hit yang sesuai dengan kursor.
Mari kita lihat alasannya.
Mengapa kita melakukan ini?
Jadi, katakanlah kotak di sini adalah gambar bagus yang ingin kita tingkatkan skalanya.
Saat Anda menggunakan dua jari pada trackpad untuk menskalakan, ada kemungkinan salah satu dari dua jari palsu tersebut tidak mengenai elemen.
Jalur Kliknya tidak akan berpotongan dengan gambar, dan akan dimulai di luar batas.
Jadi, alih-alih diskalakan, gambar mungkin akan di-scroll.
Kemudian, jika ada elemen lain yang dapat di-scroll di luar gambar, mungkin elemen tersebut juga akan mulai di-scroll bersamaan.
Ini bukan yang diinginkan pengguna.
Mereka ingin meningkatkan skala.
Jadi, yang kami lakukan sekarang adalah, alih-alih mengirimkan melalui jari palsu tersebut, kami sekarang mengirimkan gestur penskalaan hanya ke elemen di bawah posisi kursor, yang kemudian menghasilkan perilaku yang benar.
Di mana pun kursor berada atau seberapa dekat kursor dengan tepi elemen yang ingin Anda skalakan, elemen tersebut kini akan diskalakan dengan benar.
Jadi, kabar baiknya adalah peristiwa input yang ditafsirkan ulang ini digunakan secara default dalam komponen seperti scrollable dan transformable untuk memberikan perilaku fidelitas yang lebih tinggi untuk input trackpad jika Anda menggunakan elemen penyusun dasar tersebut.
Dan jika Anda menggunakan apa pun yang dibuat di atasnya, Anda akan mendapatkan perilaku yang ditingkatkan tersebut dengan mengupdate versi Compose ke versi terbaru.
Dan jika Anda menulis pengubah input pointer kustom, sebaiknya lihat API baru ini dan pastikan Anda mendukungnya untuk memberikan pengalaman terbaik kepada pengguna di semua perangkat input yang berbeda ini.
Dan, tentu saja, kami juga menambahkan API pengujian, sehingga Anda juga dapat memeriksa apakah aplikasi Anda menangani semua jenis input yang berbeda ini dengan benar.
Jadi, performTrackpadInput terlihat sangat mirip dengan API pengujian yang ada untuk mouse dan sentuh.
onNodeWithContentDescription("Photo")
.performTrackpadInput {
click(center)
pan(Offset(0f, 100f))
scale(0.9f)
}Dengan menggunakan semua itu, Anda dapat memvalidasi bahwa aplikasi Anda berfungsi dengan benar, apa pun perangkat input yang digunakan pengguna di perangkat Anda.
Jadi, semoga ini memberi Anda gambaran yang jauh lebih baik tentang bagaimana peristiwa pointer beralih dari jari di touchpad hingga ke aplikasi Anda.
Sekarang, saya akan menyerahkan kepada Jeremy untuk membahas cara yang sangat berbeda dalam penggunaan trackpad.
Terima kasih.
Oke.
Halo, saya Jeremy Walker.
Saya sering menangani input, dan saya pikir akan menarik jika saya memberi tahu Anda beberapa hal baru yang kami lakukan dengan input Compose dan pengaruhnya terhadap Anda.
Dan khususnya dengan jenis input tidak langsung ini, yang muncul karena input baru berdasarkan faktor bentuk baru: kacamata AI.
Jadi, saat Anda mendapatkan input dari kacamata, Anda dapat melakukannya dengan beberapa cara: Anda dapat melihat sesuatu, Anda dapat menggunakan suara, Anda dapat menggunakan gestur, tetapi saya akan membahas touchpad secara khusus.
Dan ini sedikit berbeda dari yang dibicarakan Alex, karena letaknya di samping kepala, vertikal, sangat lebar, dan sangat pendek.
Jadi, saat kami memikirkan cara kerjanya di Compose, jika Anda membayangkan Anda melihat tombol kecil di depan Anda, jika Anda menggerakkan kursor untuk mencoba menyentuhnya, itu tidak akan menjadi pengalaman yang menyenangkan, bukan?
Jadi, bagaimana kita akan mendukungnya?
Sebagai pengingat, ini adalah tampilan UI Kacamata.
Kacamata ini dirancang secara unik untuk menampilkan konten dengan lancar di ruang pandang Anda.
Tapi, sangat sederhana, seperti, kami mencoba membuatnya tetap sederhana.
Dan jika kita melihat contoh di sini, Anda dapat melihat bahwa ini adalah daftar.
Fokusnya adalah pada elemen tertentu di tengah.
Apa yang sebenarnya ingin kita lakukan?
Kita ingin memilihnya, atau mungkin beralih ke elemen sebelumnya atau berikutnya.
Kita tidak perlu lokasi layar.
Dan yang ini sedikit lebih rumit, tetapi pada dasarnya Anda dapat melihat ada tiga opsi: Anda dapat menutup telepon, membunyikan audio, atau menonaktifkan video.
Namun, Anda harus memilihnya, atau beralih ke opsi lain dan memilihnya.
Jadi, kami berpikir bahwa kita tidak perlu memetakan langsung ke lokasi di layar, atau dalam hal ini, mata Anda.
Jadi, ya, seperti inilah tampilannya.
Jadi, sebagai contoh, Anda dapat melihat di sini, saya hanya berpindah di antara elemen, dan ini ada di UI Glasses, dan ini sesuai dengan yang kita inginkan.
Dan, Anda dapat mengetuknya.
Jadi, kami melihat Android untuk memikirkan, apa yang ada di luar sana yang dapat kami gunakan untuk mendukung hal ini.
Dan jika Anda pernah mendapatkan Oh, maaf.
Ini melompat ke depan.
Saya akan coba kembali ke halaman sebelumnya.
Ini dia.
Oke.
Jadi, jika Anda pernah menggunakan salah satu perangkat ini, dan menautkannya dengan perangkat Android, Anda tahu bahwa Anda dapat dengan mudah berpindah dari elemen UI dari satu perangkat ke perangkat lainnya.
Misalnya, dengan remote, Anda dapat melihat bahwa Anda dapat Jika Anda membayangkan atau Anda telah menautkannya dengan Google TV, dan Anda memiliki seluruh petak film, Anda dapat menekan tombol panah untuk membuka film yang Anda inginkan, dan Anda dapat menekan tombol untuk memilihnya, tombol oke.
Jika Anda memiliki menu game dan pengontrol ini, Anda dapat menggunakan D-pad atau joystick untuk berpindah ke elemen UI, misalnya, dalam menu, dan memilihnya.
Sama seperti keyboard.
Jadi, ini cocok dengan yang kita inginkan di Compose.
Sekali lagi, berikut hal-hal yang dapat Anda lakukan, sehingga Anda dapat memperoleh gambaran tentang tampilannya.
Dan jika kita melihat sedikit lebih jauh ke belakang, sebenarnya ada jenis touchpad yang dipasangkan dengan TV, dan sebenarnya menggunakan sesuatu yang disebut sentuhan navigasi.
Idenya adalah koordinat x dan y sama sekali tidak disentuh dan tidak terikat ke layar.
Sensor ini hanya digunakan untuk mendeteksi gestur.
Jadi, yang Anda lakukan di sana adalah jika Anda menggeser ke kanan, Anda dapat membayangkan itu seperti menekan tombol panah untuk melanjutkan.
Jika menggeser ke kiri, Anda akan bergerak ke kiri, atas, dan bawah.
Jadi, ini memberi kita sebagian besar hal yang kita inginkan.
Anda hanya menggunakan x dan y untuk pelacakan kecepatan guna mengetahui geser dan geser cepat, dll. Jadi, hal itu memberi kita sebagian besar hal yang ingin kita mulai di Compose.
Tidak persis karena dipetakan ke TV, jadi kita harus memastikan kita tidak menggunakan rute TV, kita tidak mengacaukan TV nanti, jadi kita harus memastikan kita membaginya, tetapi itu adalah sesuatu yang akan kita bahas nanti.
Namun, ini memberi kita semacam titik awal.
Agar kita dapat menggunakan jenis navigasi sentuh ini.
Jadi, oke.
Seperti apa desain API-nya?
Nah, di Compose, input yang paling umum atau paling sering digunakan adalah sentuhan, bukan?
Jadi, kami memiliki banyak pekerjaan terkait hal itu.
Jadi, kami harus mencari tahu hubungannya dengan hal itu.
Sebagai pengingat, berikut adalah tampilan PointerEvent.
Anda dapat melihat di sini bahwa Anda memiliki jenis yang merupakan jenis gerakan ke bawah di atas, lalu Anda memiliki PointerInputChange ini yang hanya berupa daftar. Anda dapat menganggapnya sebagai jari.
Jika Anda memiliki tiga jari yang ditekuk, Anda akan memiliki tiga hal dalam daftar.
Jadi, kami ingin tampilannya terlihat seperti ini.
Ini bukan modul UI, yang merupakan modul yang jauh lebih rendah daripada yang digunakan sebagian besar developer saat menangani input.
Mereka akan menjadi lapisan di atas lapisan fondasi.
Dan di situlah semua detektor gestur kita berada.
Karena sebagai developer, Anda tidak peduli dengan semua hal ini, seperti input menit.
Anda hanya ingin tahu, apakah terjadi penyeretan, apakah terjadi klik, apakah terjadi geser, lalu Anda melakukan tindakan berdasarkan hal tersebut.
Jadi, kami memiliki banyak kode yang melakukan hal itu untuk Anda, dan kode tersebut didukung oleh hal-hal ini di balik layar.
Jadi, kita mulai berpikir, oke, kita harus membuatnya semudah mungkin agar kode yang ada di foundation dapat dengan mudah mendukung jenis baru ini.
Jadi, kami membuat jenis baru yang terlihat hampir sama.
Hanya saja, ini disebut tidak langsung.
Dan tidak langsung berarti tidak ada sentuhan langsung pada layar.
Jadi, Anda akan tahu bahwa, fitur ini akan hadir. Jangan pikirkan hal ini dari sudut pandang sentuhan.
Bayangkan kita hanya melakukan penanganan gestur di sini dan menavigasi di antara elemen UI.
Jenisnya sama.
Ada daftar jari.
Dalam hal ini, IndirectPointerInputChange.
Namun, kami melakukannya, dan hasilnya sangat bagus.
Namun, ada satu item lagi yang kami temukan, yaitu Primary Directional Motion Axis.
Mungkin terdengar rumit, tetapi akan masuk akal saat saya menjelaskannya, karena prosesnya cukup menarik.
Jadi, bagaimana hal itu bisa terjadi?
Sekali lagi, Anda memiliki touchpad ini di sisi kepala, dan touchpad ini lebar dan pendek.
Jadi, pada tahap ini, kami memiliki ide seperti, oke, kami memiliki navigasi sentuh.
Jadi, kita bisa menggeser ke kiri dan ke kanan.
Dan itu berfungsi dengan baik.
Namun, jika Anda memikirkan bagaimana trackpad ada sekarang, bukan?
Saat Anda menggeser ke kiri atau kanan, Anda akan menggeser ke kiri atau kanan di trackpad dengan konten UI Anda.
Jika Anda menggeser ke atas atau ke bawah, Anda akan men-scroll daftar ke atas atau ke bawah.
Jadi, jika Anda mencoba melakukannya dengan kacamata, seperti ini tidak terlalu buruk, bukan?
Namun, jika Anda melakukannya, pengalamannya tidak akan terlalu bagus.
Jadi, yang kami temukan adalah gerakan yang paling alami adalah ketukan, tetapi dengan menggeser di sepanjang sisi kacamata.
Jadi, kami melakukan banyak studi dengan pengguna, dan mereka sebenarnya berharap bahwa saat Anda menggeser secara horizontal, Anda tidak benar-benar memindahkan konten secara horizontal, melainkan secara vertikal.
Anda dapat memikirkan hal ini jika Anda mencobanya dalam pikiran Anda, seperti saat Anda menggeser di sini, jika Anda memiliki daftar di depan Anda, seperti maju, Anda dapat maju melalui daftar atau Anda dapat kembali melalui daftar.
Jadi, kita mengambil input dua dimensi dan mencoba memikirkannya dengan cara satu dimensi.
Dari situlah ide untuk Sumbu Gerakan Utama ini muncul, yaitu Anda dapat bergerak secara horizontal dan elemen akan bergerak secara vertikal.
Jadi, Anda dapat menentukannya di perangkat itu sendiri.
Anda bisa bilang, hei, ini bukan trackpad biasa.
Saya ingin arah utamanya horizontal, dan itu adalah satu-satunya sumbu yang ingin saya ikuti.
Jadi, dari situlah asalnya.
Oke.
Jadi, kami merasa cukup puas dengan hal itu.
Compose menangani semuanya.
Dan Anda memiliki implementasi vertikal yang bagus ini.
Anda dapat memikirkan hal ini.
Jadi, cara kami memetakannya adalah dengan definisi horizontal, kita hanya memiliki gerakan maju dan mundur.
Kita tidak memiliki arah atas, bawah, kiri, kanan.
Kita hanya memiliki tombol maju dan mundur.
Kemudian, kita dapat memetakan hal tersebut jika Anda sudah memahami fokus dengan berikutnya dan sebelumnya.
Jadi, sekarang kita hanya perlu beralih ke berikutnya dan sebelumnya.
Dan ini sangat cocok untuk video vertikal.
Dan bahkan lebih bagus lagi.
Solusi ini dapat langsung digunakan dengan tata letak horizontal, bukan?
Karena Anda hanya memiliki banyak item yang difokuskan.
Anda cukup membuka halaman berikutnya atau sebelumnya, dan fitur ini akan berfungsi dengan keduanya.
Jadi, ini adalah kasus dengan Compose, di mana kami mendefinisikan dan mencari tahu semuanya di Compose, tetapi akan sangat bagus jika perangkat itu sendiri dapat mengatakannya, karena perangkat tahu jika bentuknya aneh, dan tahu jika hanya menginginkan sumbu utama ini, tetapi tidak memiliki cara untuk mendefinisikannya.
Jadi, sekarang kita harus membawa konsep ini kembali ke platform dan berkata, oke, kita perlu mendefinisikan ini di platform agar kita dapat menstandarkannya dan perangkat ini sendiri dapat menentukannya, sehingga Compose dapat sepenuhnya mendukungnya hingga ke bawah.
Jadi, ada kasus saat kami bekerja di Compose dan terus maju di Compose, lalu bekerja mundur, dan membawanya bersama kami.
Jadi, itulah yang kami lakukan.
Kami membuat API baru ini agar Anda atau perangkat dapat menentukan hal tersebut.
InputDevice.ViewBehavior
.getPrimaryDirectionalMotionAxis()Dan jika Anda ingat sebelumnya, saat saya berbicara tentang input sentuh, atau, navigasi sentuh, saya berbicara tentang bagaimana navigasi sentuh terutama ditujukan untuk TV.
Kami tidak ingin merusak implementasi tersebut.
Jadi, kami menambahkan kolom lain untuk menentukan jenis input kaca baru ini.
Oke.
Jadi, pada akhirnya, apa artinya bagi Anda?
Ini adalah versi yang lebih spesifik dari apa yang Anda dapatkan sebagai pendeteksi gestur.
// Glimmer Library
Box(
modifier =
Modifier.fillMaxSize()
.onIndirectPointerGesture(
enabled = true,
onSwipeForward = { /* onSwipeForward */ },
onSwipeBackward = { /* onSwipeBackward */ },
onClick = { /* onClick */ },
)
.focusTarget()
) {
// App()Secara default, jika Anda menggunakan Foundation, fitur ini akan langsung berfungsi dengan detektor gestur.
Kami telah melakukan pekerjaan ini untuk Anda, jadi Anda tidak perlu melakukan apa pun.
Namun, jika Anda ingin membuat aplikasi untuk kacamata, Anda dapat menggunakan library Glimmer kami, dan kami memiliki detektor gestur khusus, yang hanya memberi Anda, Anda tahu, jadi Anda tidak perlu menggabungkannya, Anda dapat menggunakan yang ini saja, mendapatkan klik, frame maju, dan mundur.
Oke.
Jadi, kita telah membahas cara kerja API itu sendiri, di platform dan di Compose.
Bagaimana dengan pengujian?
Jadi, seperti inilah tampilan sentuhan saat Anda ingin melakukan pengujian sentuh.
@Test
clickTest {
rule.onNodeWithTag(defaultTag)
.performTouchInput
{ click(center) }
}Anda hanya perlu mengucapkan performTouchInput, lalu memberikan gestur.
Ada banyak gestur yang berbeda dan kami membangun semua peristiwa kecil untuk membuat gestur tersebut terjadi.
Bagaimana cara kerjanya di tingkat umum?
Anda memiliki modul Compose UI, modul UI Testing, dan keduanya berkomunikasi, setidaknya dalam hal input, menggunakan MotionEvent.
Selain itu, modul Pengujian UI juga menggunakan mekanisme antrean, yang semuanya didasarkan pada MotionEvent.
Mengapa kami memberi tahu Anda hal ini?
Karena Anda tidak dapat membuat MotionEvent secara terprogram yang seperti peristiwa input tidak langsung, yang sangat bagus bagi saya karena itu berarti saya harus menulis ulang semua komunikasi antara modul dan sistem antrean.
Tapi saya berhasil.
Jadi, apa artinya bagi Anda?
Jika Anda terbiasa dengan pengujian input sentuh, inilah yang Anda dapatkan untuk input tidak langsung.
Anda cukup menambahkan indirect ke nama.
@Test
clickTest {
rule.onNodeWithTag(defaultTag)
// .performTouchInput
.performIndirectPointerInput (
IndirectPointerEventPrimaryDirectionalMotionAxis.X,
inputDeviceSize,
)
{ click(center) }
}Sekarang, saya meneruskan beberapa parameter tambahan.
Anda mungkin mengenali yang pertama, yaitu tempat Anda menentukan horizontal.
Lalu, ukuran inputnya tentu saja adalah ukuran touchpad.
Sekarang, hal ini tidak banyak berubah.
Jadi, jika Anda melihat kode sumbernya, Anda dapat melihat bahwa saya baru saja menulis fungsi ekstensi dan terlihat seperti ini.
@Test
clickTest {
rule.onNodeWithTag(defaultTag)
// .performTouchInput
.performIndirectPointerInput
{ click(center) }
}Oke.
Jadi, itu memberi Anda, itu seharusnya memberi Anda gambaran tentang semua pekerjaan yang kami lakukan hanya untuk mendukung trackpad pada bingkai kacamata Anda, atau pada kacamata AI.
Namun, kami melakukan ini, saya juga melakukan latihan ini untuk pelacakan mata dan tangan, jadi masih banyak lagi yang akan datang.
Jadi, secara umum, apa yang ingin saya sampaikan kepada Anda?
Jadi, baik Anda menggunakan trackpad dengan ponsel atau kacamata atau input lainnya, kami memikirkan hal itu dan mencoba melakukan pekerjaan tersebut terlebih dahulu.
Jadi, jika Anda menggunakan pendeteksi gestur Foundation ini, fitur ini akan langsung berfungsi.
Itu yang pertama.
Kedua, Compose adalah toolkit UI utama, dan kami akan terus mengeksplorasi dan mendukung jenis input baru, baik di platform maupun di toolkit, yang dapat Anda lihat di sini.
Kemudian, tentu saja, untuk menguji API, saya ingin mempertahankan platform dan paradigma yang sudah dikenal sehingga Anda dapat bermigrasi dan menguji jenis baru ini dengan semudah mungkin.
Terima kasih, semoga informasi ini membantu.
onNodeWithContentDescription("Photo")
.performTrackpadInput {
click(center)
pan(Offset(0f, 100f))
scale(0.9f)
}InputDevice.ViewBehavior
.getPrimaryDirectionalMotionAxis()// Glimmer Library
Box(
modifier =
Modifier.fillMaxSize()
.onIndirectPointerGesture(
enabled = true,
onSwipeForward = { /* onSwipeForward */ },
onSwipeBackward = { /* onSwipeBackward */ },
onClick = { /* onClick */ },
)
.focusTarget()
) {
// App()@Test
clickTest {
rule.onNodeWithTag(defaultTag)
.performTouchInput
{ click(center) }
}@Test
clickTest {
rule.onNodeWithTag(defaultTag)
// .performTouchInput
.performIndirectPointerInput (
IndirectPointerEventPrimaryDirectionalMotionAxis.X,
inputDeviceSize,
)
{ click(center) }
}@Test
clickTest {
rule.onNodeWithTag(defaultTag)
// .performTouchInput
.performIndirectPointerInput
{ click(center) }
}