Saat layanan aksesibilitas menjelajahi elemen di layar, elemen-elemen ini harus dikelompokkan, dipisahkan, atau bahkan disembunyikan pada tingkat perincian yang tepat. Jika setiap satu composable level rendah di layar Anda ditandai secara independen, pengguna harus banyak berinteraksi untuk berpindah-pindah di layar. Jika elemen digabungkan dengan terlalu agresif, pengguna mungkin tidak memahami elemen mana yang secara logis menjadi satu. Jika ada elemen di layar yang murni dekoratif, elemen ini dapat disembunyikan dari layanan aksesibilitas. Dalam kasus ini, Anda dapat menggunakan Compose API untuk menggabungkan, menghapus, dan menyembunyikan semantik.
Menggabungkan semantik
Saat Anda menerapkan pengubah clickable ke composable induk, Compose
akan otomatis menggabungkan semua elemen turunan di bawahnya. Untuk memahami cara
komponen Foundation dan Material Compose interaktif menggunakan strategi penggabungan
secara default, lihat bagian Elemen interaktif.
Komponen biasanya terdiri dari beberapa composable. Composable ini dapat membentuk grup logis dan masing-masing dapat berisi informasi penting, tetapi Anda mungkin tetap ingin layanan aksesibilitas melihatnya sebagai satu elemen.
Misalnya, bayangkan composable yang menampilkan avatar pengguna, nama mereka, dan beberapa informasi tambahan:
Anda dapat mengaktifkan Compose untuk menggabungkan elemen ini dengan menggunakan parameter mergeDescendants
dalam pengubah semantik. Dengan cara ini, layanan aksesibilitas memperlakukan
komponen sebagai satu entity, dan semua properti semantik turunan
digabungkan:
@Composable private fun PostMetadata(metadata: Metadata) { // Merge elements below for accessibility purposes Row(modifier = Modifier.semantics(mergeDescendants = true) {}) { Image( imageVector = Icons.Filled.AccountCircle, contentDescription = null // decorative ) Column { Text(metadata.author.name) Text("${metadata.date} • ${metadata.readTimeMinutes} min read") } } }
Layanan aksesibilitas kini akan berfokus pada seluruh container sekaligus, dan menggabungkan kontennya:
Setiap properti semantik memiliki strategi penggabungan yang ditetapkan. Misalnya, properti
ContentDescription menambahkan semua nilai ContentDescription turunan
ke daftar. Anda dapat memeriksa strategi penggabungan properti semantik dengan
memeriksa implementasi mergePolicy-nya di SemanticsProperties.kt.
Properti dapat mengambil nilai induk atau turunan, menggabungkan nilai ke dalam daftar atau string, tidak mengizinkan penggabungan sama sekali dan menampilkan pengecualian, atau strategi penggabungan kustom lainnya.
Ada skenario lain saat Anda mengharapkan semantik turunan digabungkan ke
semantik induk, tetapi hal itu tidak terjadi. Dalam contoh berikut, kita memiliki
induk item daftar clickable dengan elemen turunan, dan kita mungkin mengharapkan
induk menggabungkan semuanya:
@Composable private fun ArticleListItem( openArticle: () -> Unit, addToBookmarks: () -> Unit, ) { Row(modifier = Modifier.clickable { openArticle() }) { // Merges with parent clickable: Icon( painter = painterResource(R.drawable.ic_logo), contentDescription = "Article thumbnail" ) ArticleDetails() // Defies the merge due to its own clickable: BookmarkButton(onClick = addToBookmarks) } }
Saat pengguna menekan item clickable Row, artikel akan terbuka. Di dalamnya, ada BookmarkButton untuk mem-bookmark artikel. Tombol bertingkat ini
muncul sebagai tidak digabungkan, sedangkan konten turunan lainnya di dalam baris
digabungkan:
Row. Hierarki yang tidak digabungkan berisi node terpisah untuk setiap composable Text.Beberapa composable tidak otomatis digabungkan di bawah induk, sesuai desain. Induk
tidak dapat menggabungkan turunannya saat turunan juga digabungkan, baik
dari setelan mergeDescendants = true secara eksplisit maupun dengan menjadi komponen yang
menggabungkan dirinya sendiri, seperti tombol atau elemen yang dapat diklik. Mengetahui cara API tertentu digabungkan atau
tidak digabungkan dapat membantu Anda men-debug beberapa perilaku yang berpotensi tidak terduga.
Gunakan penggabungan jika elemen turunan merupakan grup yang logis dan masuk akal
di bawah induknya. Namun, jika turunan bertingkat memerlukan penyesuaian manual atau penghapusan
semantiknya sendiri, API lain mungkin lebih sesuai dengan kebutuhan Anda (misalnya,
clearAndSetSemantics).
Menghapus dan menetapkan semantik
Jika informasi semantik perlu dihapus atau ditimpa sepenuhnya, API yang efektif untuk digunakan adalah clearAndSetSemantics.
Jika komponen memerlukan semantiknya sendiri dan semantik turunannya dihapus, gunakan API ini dengan lambda kosong. Jika semantiknya harus ditimpa, sertakan konten baru Anda di dalam lambda.
Perhatikan bahwa saat menghapus dengan lambda kosong, semantik yang dihapus tidak
dikirim ke konsumen mana pun yang menggunakan informasi ini, seperti aksesibilitas, isi otomatis,
atau pengujian. Saat menimpa konten dengan
clearAndSetSemantics{/*semantic information*/}, semantik baru akan menggantikan semua
semantik elemen dan turunannya sebelumnya.
Berikut adalah contoh komponen tombol kustom, yang direpresentasikan oleh baris yang dapat berinteraksi dengan ikon dan teks:
// Developer might intend this to be a toggleable. // Using `clearAndSetSemantics`, on the Row, a clickable modifier is applied, // a custom description is set, and a Role is applied. @Composable fun FavoriteToggle() { val checked = remember { mutableStateOf(true) } Row( modifier = Modifier .toggleable( value = checked.value, onValueChange = { checked.value = it } ) .clearAndSetSemantics { stateDescription = if (checked.value) "Favorited" else "Not favorited" toggleableState = ToggleableState(checked.value) role = Role.Switch }, ) { Icon( imageVector = Icons.Default.Favorite, contentDescription = null // not needed here ) Text("Favorite?") } }
Meskipun ikon dan teks memiliki beberapa informasi semantik, keduanya tidak menunjukkan bahwa komponen ini dapat diubah statusnya. Penggabungan tidak cukup karena Anda harus memberikan informasi tambahan tentang komponen.
Karena cuplikan di atas membuat komponen tombol kustom, Anda perlu menambahkan
kemampuan tombol, serta semantik stateDescription,
toggleableState, dan role. Dengan cara ini, status
komponen dan tindakan terkait akan tersedia—misalnya, TalkBack mengumumkan
"Ketuk dua kali untuk beralih", bukan "Ketuk dua kali untuk mengaktifkan".
Dengan menghapus semantik asli dan menetapkan semantik baru yang lebih deskriptif, layanan aksesibilitas kini dapat melihat bahwa ini adalah komponen yang dapat diganti yang dapat mengubah status.
Saat menggunakan clearAndSetSemantics, pertimbangkan hal berikut:
- Karena layanan tidak menerima informasi saat API ini ditetapkan, sebaiknya gunakan API ini seperlunya.
- Informasi semantik berpotensi digunakan oleh agen AI dan layanan serupa untuk memahami layar, sehingga hanya boleh dihapus jika diperlukan.
- Semantik kustom dapat ditetapkan dalam lambda API.
- Urutan pengubah sangat penting―API ini menghapus semua semantik yang ada setelah diterapkan, terlepas dari strategi penggabungan lainnya.
Menyembunyikan semantik
Dalam beberapa skenario, elemen tidak perlu dikirim ke layanan
aksesibilitas—mungkin informasi tambahannya redundan untuk aksesibilitas,
atau murni dekoratif secara visual dan non-interaktif. Dalam kasus ini, Anda
dapat menyembunyikan elemen dengan API hideFromAccessibility.
Dalam contoh berikut, ada komponen yang mungkin perlu disembunyikan: watermark redundan yang mencakup komponen, dan karakter yang digunakan untuk memisahkan informasi secara dekoratif.
@Composable fun WatermarkExample( watermarkText: String, content: @Composable () -> Unit, ) { Box { WatermarkedContent() // Mark the watermark as hidden to accessibility services. WatermarkText( text = watermarkText, color = Color.Gray.copy(alpha = 0.5f), modifier = Modifier .align(Alignment.BottomEnd) .semantics { hideFromAccessibility() } ) } } @Composable fun DecorativeExample() { Text( modifier = Modifier.semantics { hideFromAccessibility() }, text = "A dot character that is used to decoratively separate information, like •" ) }
Penggunaan hideFromAccessibility di sini memastikan watermark dan dekorasi
disembunyikan dari layanan aksesibilitas, tetapi tetap mempertahankan semantiknya untuk kasus penggunaan
lain, seperti pengujian.
Perincian kasus penggunaan
Berikut adalah ringkasan kasus penggunaan untuk memahami cara membedakan API sebelumnya dengan jelas:
- Jika konten tidak dimaksudkan untuk digunakan oleh layanan aksesibilitas:
- Gunakan
hideFromAccessibilityjika konten mungkin bersifat dekoratif atau redundan, tetapi masih harus diuji. - Gunakan
clearAndSetSemantics{}dengan lambda kosong saat semantik induk dan turunan perlu dihapus untuk semua layanan. - Gunakan
clearAndSetSemantics{/*content*/}dengan konten di dalam lambda saat semantik komponen perlu ditetapkan secara manual.
- Gunakan
- Jika konten harus diperlakukan sebagai satu entity, dan memerlukan semua informasi turunannya agar lengkap:
- Gunakan gabungkan turunan semantik.
Direkomendasikan untuk Anda
- Catatan: teks link ditampilkan saat JavaScript nonaktif
- Aksesibilitas di Compose
- [Desain Material 2 di Compose][19]
- Menguji tata letak Compose Anda