Semantik di Compose

Komposisi menjelaskan UI aplikasi Anda dan dihasilkan dengan menjalankan composable. Komposisinya adalah struktur pohon yang terdiri dari composable yang mendeskripsikan UI Anda.

Di samping Komposisi, terdapat pohon paralel yang disebut semantik hierarki. Pohon ini menjelaskan UI Anda dengan cara alternatif yang dimengerti untuk layanan Aksesibilitas dan untuk Pengujian Google Workspace for Education. Layanan aksesibilitas menggunakan hierarki untuk mendeskripsikan aplikasi kepada pengguna dengan kebutuhan tertentu. Framework pengujian menggunakan hierarki untuk berinteraksi dengan aplikasi Anda dan membuat pernyataan tentangnya. Hierarki Semantik tidak berisi informasi tentang cara menggambar composable, tetapi berisi informasi tentang makna semantik composable Anda.

Hierarki UI standar dan pohon semantiknya
Gambar 1. Hierarki UI standar dan hierarki semantiknya.

Jika aplikasi Anda terdiri atas composable dan pengubah dari library foundation dan material Compose, pohon Semantik akan otomatis diisi dan dibuat untuk Anda. Namun, ketika menambahkan composable tingkat rendah kustom, Anda harus menyediakan semantiknya secara manual. Mungkin juga ada situasi saat pohon Anda salah atau tidak sepenuhnya mewakili makna dari elemen di layar, dan Anda dapat menyesuaikan pohonnya.

Misalnya, perhatikan composable kalender kustom ini:

Composable kalender kustom dengan elemen hari yang dapat dipilih
Gambar 2. Composable kalender kustom dengan elemen hari yang dapat dipilih.

Dalam contoh ini, seluruh kalender diimplementasikan sebagai satu composable tingkat rendah menggunakan composable Layout dan menggambar langsung ke Canvas. Jika Anda tidak melakukan apa pun, layanan aksesibilitas tidak akan menerima informasi tentang konten composable dan pilihan pengguna dalam kalender. Misalnya, jika pengguna mengklik pada hari yang berisi 17, framework aksesibilitas hanya akan menerima informasi deskripsi untuk seluruh kontrol kalender. Dalam hal ini, layanan aksesibilitas TalkBack akan mengumumkan "Kalender" atau, hanya sedikit lebih baik, "Kalender April" dan pengguna akan bertanya-tanya hari apa yang dipilih. Untuk membuat composable ini lebih dapat diakses, Anda harus menambahkan informasi semantik secara manual.

Properti semantik

Semua node di pohon UI dengan beberapa makna semantik memiliki node paralel di pohon Semantik. Node di pohon Semantik berisi properti yang menyajikan makna composable yang sesuai. Misalnya, Text composable berisi properti semantik text, karena itulah makna dari composable tersebut. Icon berisi properti contentDescription (jika ditetapkan oleh developer) yang menyampaikan arti Icon dalam teks. Composable dan pengubah yang dibuat berdasarkan fondasi Compose library telah menetapkan properti yang relevan untuk Anda. Secara opsional, atur atau mengganti properti sendiri dengan semantics dan Pengubah clearAndSetSemantics. Misalnya, tambahkan kustom tindakan aksesibilitas ke node, memberikan status alternatif deskripsi untuk elemen yang dapat diganti statusnya, atau menunjukkan bahwa teks tertentu composable harus dianggap sebagai judul.

Untuk memvisualisasikan hierarki Semantik, gunakan Alat Layout Inspector atau gunakan Metode printToLog() di dalam pengujian. Ini akan mencetak nilai Hierarki semantik di dalam Logcat.

class MyComposeTest {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun MyTest() {
        // Start the app
        composeTestRule.setContent {
            MyTheme {
                Text("Hello world!")
            }
        }
        // Log the full semantics tree
        composeTestRule.onRoot().printToLog("MY TAG")
    }
}

Output pengujian ini adalah:

    Printing with useUnmergedTree = 'false'
    Node #1 at (l=0.0, t=63.0, r=221.0, b=120.0)px
     |-Node #2 at (l=0.0, t=63.0, r=221.0, b=120.0)px
       Text = '[Hello world!]'
       Actions = [GetTextLayoutResult]

Pertimbangkan cara properti semantik menyampaikan arti composable. Pertimbangkan Switch. Ini yang akan dilihat pengguna:

Gambar 3. Sakelar saat "Aktif" dan "Nonaktif" negara bagian..

Untuk mendeskripsikan makna elemen ini, Anda dapat mengucapkan hal berikut: "This adalah {i>Switch<i}, yang merupakan elemen yang dapat dialihkan dalam tombol 'On' status. Anda dapat mengkliknya berinteraksi dengannya."

Inilah kegunaan properti semantik yang sebenarnya. Node semantik elemen Switch ini berisi properti berikut, seperti yang divisualisasikan dengan Layout Inspector:

Layout Inspector menampilkan properti Semantik composable Switch
Gambar 4. Layout Inspector menampilkan properti Semantik dari composable Switch.

Role menunjukkan jenis elemen. StateDescription menjelaskan cara "Aktif" harus direferensikan. Secara {i>default<i}, ini adalah versi yang dilokalkan dari kata "Aktif", tetapi Anda dapat membuatnya lebih spesifik (misalnya, "Diaktifkan") berdasarkan berdasarkan konteks. ToggleableState adalah status Tombol saat ini. Tujuan Properti OnClick mereferensikan metode yang digunakan untuk berinteraksi dengan elemen ini. Sebagai daftar lengkap properti semantik, lihat SemanticsProperties . Untuk daftar lengkap Tindakan Aksesibilitas yang mungkin, lihat objek SemanticsActions.

Melacak properti semantik dari setiap composable di aplikasi Anda akan membuka berbagai kemungkinan yang canggih. Beberapa contohnya:

  • Talkback menggunakan properti untuk membacakan dengan lantang apa yang ditampilkan di layar dan memungkinkan pengguna berinteraksi dengan lancar. Untuk composable Switch, Talkback mungkin ucapkan: "Aktif; Beralih; ketuk dua kali untuk beralih". Pengguna dapat mengetuk dua kali layar untuk menonaktifkan Tombol.
  • Framework pengujian menggunakan properti untuk menemukan node, berinteraksi dengannya, dan membuat pernyataan. Contoh pengujian untuk Tombol akses adalah:
    val mySwitch = SemanticsMatcher.expectValue(
        SemanticsProperties.Role, Role.Switch
    )
    composeTestRule.onNode(mySwitch)
        .performClick()
        .assertIsOff()

Pohon Semantik yang digabungkan dan yang tidak digabungkan

Seperti yang disebutkan sebelumnya, setiap composable di pohon UI mungkin memiliki nol atau beberapa properti semantik yang ditetapkan. Ketika composable belum menetapkan properti semantik, tidak disertakan sebagai bagian dari hierarki Semantik. Dengan demikian, pohon Semantik hanya berisi node yang benar-benar berisi makna semantik. Akan tetapi, terkadang menyampaikan makna yang benar dari informasi yang ditampilkan di layar juga berguna untuk menggabungkan sub-pohon tertentu dari node dan memperlakukannya sebagai node. Begitulah Anda dapat memikirkan tentang satu set {i>node<i} secara keseluruhan, daripada berurusan dengan masing-masing node turunan satu per satu. Prinsipnya adalah, setiap node dalam pohon ini mewakili elemen yang dapat difokuskan selama menggunakan layanan Aksesibilitas.

Contoh composable semacam ini adalah Button. Anda dapat memberi alasan tentang tombol sebagai elemen tunggal, meskipun dapat berisi beberapa node turunan:

Button(onClick = { /*TODO*/ }) {
    Icon(
        imageVector = Icons.Filled.Favorite,
        contentDescription = null
    )
    Spacer(Modifier.size(ButtonDefaults.IconSpacing))
    Text("Like")
}

Di hierarki Semantik, properti turunan tombol digabungkan, dan tombolnya ditampilkan sebagai node daun tunggal di hierarki:

Penggabungan representasi semantik satu daun
Gambar 5. Menggabungkan representasi semantik satu daun.

Composable dan pengubah dapat menunjukkan bahwa keduanya ingin menggabungkan properti semantik turunannya dengan memanggil Modifier.semantics (mergeDescendants = true) {}. Menyetel properti ini ke true menunjukkan bahwa properti semantik harus digabungkan. Dalam contoh Button, Button composable menggunakan pengubah clickable secara internal yang menyertakan Pengubah semantics. Oleh karena itu, node turunan tombol digabungkan. Baca dokumentasi aksesibilitas untuk mempelajari lebih lanjut kapan Anda harus mengubah menggabungkan perilaku di composable Anda.

Beberapa pengubah dan composable di library Foundation dan Material Compose memiliki kumpulan properti ini. Misalnya, pengubah clickable dan toggleable akan otomatis menggabungkan turunannya. Selain itu, composable ListItem akan menggabungkan turunannya.

Periksa hierarki

Pohon semantik sebenarnya adalah dua pohon yang berbeda. Ada Semantik digabungkan pohon, yang menggabungkan node turunan saat mergeDescendants ditetapkan ke true. Ada juga hierarki Semantik yang terpisah, yang tidak menerapkan penggabungan, tetapi menjaga setiap {i>node<i} tetap utuh. Layanan aksesibilitas menggunakan hierarki yang terpisah dan menerapkannya algoritma penggabungannya sendiri, dengan mempertimbangkan mergeDescendants saat ini. Framework pengujian secara default menggunakan hierarki gabungan.

Anda dapat memeriksa kedua pohon tersebut menggunakan metode printToLog(). Secara {i>default<i}, seperti pada contoh sebelumnya, pohon yang digabungkan akan dicatat. Untuk mencetak pohon yang dipisahkan sebagai gantinya, tetapkan parameter useUnmergedTree dari pencocok onRoot() ke true:

composeTestRule.onRoot(useUnmergedTree = true).printToLog("MY TAG")

Layout Inspector memungkinkan Anda menampilkan Semantik yang digabungkan dan yang tidak digabungkan hierarki, dengan memilih yang diinginkan pada filter tampilan:

Opsi tampilan Layout Inspector, yang memungkinkan tampilan hierarki Semantik yang digabungkan dan terpisah
Gambar 6. Opsi tampilan Layout Inspector, yang memungkinkan tampilan hierarki Semantik yang digabungkan dan dipisahkan.

Untuk setiap node di pohon Anda, Layout Inspector akan menampilkan Semantik Gabungan dan Semantik yang ditetapkan di node tersebut dalam panel properti:

Properti semantik digabungkan dan ditetapkan
Gambar 7. Properti semantik digabungkan dan ditetapkan.

Secara default, pencocok dalam Framework Pengujian menggunakan pohon Semantik gabungan. Itulah sebabnya Anda dapat berinteraksi dengan Button dengan mencocokkan teks yang ditampilkan di dalamnya hal tersebut:

composeTestRule.onNodeWithText("Like").performClick()

Ganti perilaku ini dengan menyetel parameter useUnmergedTree dari pencocok untuk true, seperti dengan pencocok onRoot.

Perilaku penggabungan

Saat composable menunjukkan bahwa turunannya harus digabungkan, bagaimana penggabungan ini sebenarnya dilakukan?

Setiap properti semantik memiliki strategi penggabungan yang ditetapkan. Misalnya, Properti ContentDescription menambahkan semua nilai ContentDescription turunan ke daftar. Periksa strategi penggabungan properti semantik dengan memeriksa Implementasi mergePolicy di SemanticsProperties.kt. Properti dapat menggunakan nilai induk atau turunan, menggabungkan nilai-nilai tersebut ke dalam daftar atau {i>string<i}, tidak memungkinkan penggabungan sama sekali dan melemparkan pengecualian sebagai gantinya, atau strategi penggabungan kustom.

Catatan penting adalah bahwa turunan yang telah menetapkan mergeDescendants = true tidak akan disertakan dalam penggabungan. Lihat contoh berikut:

Item daftar dengan gambar, beberapa teks, dan ikon bookmark
Gambar 8. Item daftar dengan gambar, teks, dan ikon bookmark.

Berikut adalah item daftar yang dapat diklik. Saat pengguna menekan baris, aplikasi akan membuka halaman detail artikel, tempat pengguna dapat membaca artikel. Di dalam item daftar, terdapat tombol untuk mem-bookmark artikel, yang membentuk elemen yang dapat diklik bertingkat, sehingga tombol muncul secara terpisah dalam pohon yang digabungkan. Konten lainnya yang ada di baris digabungkan:

Pohon gabungan berisi beberapa teks dalam daftar di dalam node Baris. Pohon terpisah berisi node yang terpisah untuk setiap komposisi Teks.
Gambar 9. Pohon gabungan berisi beberapa teks dalam daftar di dalam node Baris. Hierarki yang dipisahkan berisi node terpisah untuk setiap composable Text.

Menyesuaikan hierarki Semantik

Seperti yang disebutkan sebelumnya, Anda dapat mengganti atau menghapus properti semantik tertentu, atau mengubah perilaku penggabungan pohon. Hal ini sangat relevan ketika Anda membuat komponen kustom sendiri. Tanpa menetapkan dan perilaku penggabungan, aplikasi Anda mungkin tidak dapat diakses, dan pengujian mungkin berperilaku berbeda dari yang Anda harapkan. Untuk membaca lebih lanjut beberapa kasus penggunaan umum di mana Anda harus menyesuaikan hierarki Semantik, baca aksesibilitas dokumentasi tambahan. Jika Anda ingin mempelajari lebih lanjut pengujian, lihat pengujian panduan kami.

Referensi lainnya