Secara default, perilaku pembaca layar aksesibilitas di aplikasi Compose diimplementasikan
dalam urutan pembacaan yang diharapkan, yaitu biasanya dari kiri ke kanan, lalu dari atas ke bawah.
Namun, ada beberapa jenis tata letak aplikasi yang membuat algoritma tidak dapat menentukan
urutan pembacaan yang sebenarnya tanpa petunjuk tambahan. Di aplikasi berbasis tampilan, Anda dapat
memperbaiki masalah tersebut menggunakan properti traversalBefore
dan traversalAfter
.
Mulai Compose 1.5, Compose menyediakan API yang sama-sama fleksibel, tetapi dengan
model konseptual baru.
isTraversalGroup
dan traversalIndex
adalah properti semantik yang
memungkinkan Anda mengontrol aksesibilitas dan urutan fokus TalkBack dalam skenario jika
algoritma pengurutan default tidak sesuai. isTraversalGroup
mengidentifikasi
grup yang penting secara semantik, sedangkan traversalIndex
menyesuaikan urutan
elemen individual dalam grup tersebut. Anda dapat menggunakan isTraversalGroup
saja,
atau dengan traversalIndex
untuk penyesuaian lebih lanjut.
Gunakan isTraversalGroup
dan traversalIndex
di
aplikasi Anda untuk mengontrol urutan traversal pembaca layar.
Mengelompokkan elemen dengan isTraversalGroup
isTraversalGroup
adalah properti boolean yang menentukan apakah node semantik adalah grup traversal atau tidak. Jenis node ini adalah node yang fungsinya berfungsi
sebagai batas atau batas dalam mengatur turunan node.
Menetapkan isTraversalGroup = true
pada node berarti semua turunan node tersebut
dikunjungi sebelum beralih ke elemen lain. Anda dapat menetapkan isTraversalGroup
pada
node yang dapat difokuskan pembaca non-layar, seperti Kolom, Baris, atau Kotak.
Contoh berikut menggunakan isTraversalGroup
. Jenis ini memunculkan empat elemen teks. Dua
elemen kiri milik satu elemen CardBox
, sedangkan dua elemen kanan
menjadi milik elemen CardBox
lainnya:
// CardBox() function takes in top and bottom sample text. @Composable fun CardBox( topSampleText: String, bottomSampleText: String, modifier: Modifier = Modifier ) { Box(modifier) { Column { Text(topSampleText) Text(bottomSampleText) } } } @Composable fun TraversalGroupDemo() { val topSampleText1 = "This sentence is in " val bottomSampleText1 = "the left column." val topSampleText2 = "This sentence is " val bottomSampleText2 = "on the right." Row { CardBox( topSampleText1, bottomSampleText1 ) CardBox( topSampleText2, bottomSampleText2 ) } }
Kode menghasilkan output yang mirip dengan berikut ini:
Karena tidak ada semantik yang ditetapkan, perilaku default pembaca layar adalah melintasi elemen dari kiri ke kanan dan dari atas ke bawah. Karena default ini, TalkBack membacakan fragmen kalimat dalam urutan yang salah:
"Kalimat ini ada di" → "Kalimat ini adalah" → "kolom kiri." → "di sebelah kanan."
Untuk mengurutkan fragmen dengan benar, ubah cuplikan asli untuk menetapkan
isTraversalGroup
ke true
:
@Composable fun TraversalGroupDemo2() { val topSampleText1 = "This sentence is in " val bottomSampleText1 = "the left column." val topSampleText2 = "This sentence is" val bottomSampleText2 = "on the right." Row { CardBox( // 1, topSampleText1, bottomSampleText1, Modifier.semantics { isTraversalGroup = true } ) CardBox( // 2, topSampleText2, bottomSampleText2, Modifier.semantics { isTraversalGroup = true } ) } }
Karena isTraversalGroup
ditetapkan secara khusus pada setiap CardBox
, batas CardBox
diterapkan saat mengurutkan elemennya. Dalam hal ini, CardBox
kiri akan dibaca terlebih dahulu, diikuti oleh CardBox
yang tepat.
Sekarang, TalkBack akan membacakan fragmen kalimat dalam urutan yang benar:
"Kalimat ini ada di" → "kolom kiri." → "Kalimat ini adalah" → "di sebelah kanan."
Menyesuaikan urutan traversal lebih lanjut
traversalIndex
adalah properti float yang memungkinkan Anda menyesuaikan urutan traversal
TalkBack. Jika mengelompokkan elemen tidak cukup bagi TalkBack untuk
berfungsi dengan benar, gunakan traversalIndex
bersama dengan
isTraversalGroup
untuk menyesuaikan urutan pembaca layar lebih lanjut.
Properti traversalIndex
memiliki karakteristik berikut:
- Elemen dengan nilai
traversalIndex
yang lebih rendah akan diprioritaskan terlebih dahulu. - Bisa positif atau negatif.
- Nilai default-nya adalah
0f
. - Hanya memengaruhi node yang dapat difokuskan pembaca layar, seperti elemen di layar seperti
teks atau tombol. Misalnya, menetapkan hanya
traversalIndex
pada kolom tidak akan berpengaruh, kecuali jika kolom memilikiisTraversalGroup
yang ditetapkan di kolom tersebut.
Contoh berikut menunjukkan cara menggunakan traversalIndex
dan
isTraversalGroup
secara bersamaan.
Contoh: Jelajahi tampilan jam
Tampilan jam adalah skenario umum saat pengurutan traversal standar tidak berfungsi. Contoh di bagian ini adalah pemilih waktu, yang memungkinkan pengguna menjelajahi angka-angka pada tampilan jam dan memilih digit untuk slot jam dan menit.
Dalam cuplikan yang disederhanakan berikut, ada CircularLayout
yang menampilkan 12
angka, dimulai dengan 12 dan bergerak searah jarum jam di sekeliling lingkaran:
@Composable fun ClockFaceDemo() { CircularLayout { repeat(12) { hour -> ClockText(hour) } } } @Composable private fun ClockText(value: Int) { Box(modifier = Modifier) { Text((if (value == 0) 12 else value).toString()) } }
Karena tampilan jam tidak dibaca secara logis dengan urutan default kiri ke kanan dan atas ke bawah, TalkBack membaca angka secara tidak berurutan. Untuk memperbaikinya, gunakan nilai penghitung yang bertambah, seperti yang ditunjukkan dalam cuplikan berikut:
@Composable fun ClockFaceDemo() { CircularLayout(Modifier.semantics { isTraversalGroup = true }) { repeat(12) { hour -> ClockText(hour) } } } @Composable private fun ClockText(value: Int) { Box(modifier = Modifier.semantics { this.traversalIndex = value.toFloat() }) { Text((if (value == 0) 12 else value).toString()) } }
Untuk menetapkan pengurutan traversal dengan benar, pertama-tama buat CircularLayout
sebagai grup traversal dan tetapkan isTraversalGroup = true
. Kemudian, saat setiap teks jam
digambar ke tata letak, setel traversalIndex
yang sesuai ke nilai
penghitung.
Karena nilai penghitung terus meningkat, setiap traversalIndex
nilai jam
menjadi lebih besar saat angka ditambahkan ke layar—nilai jam 0
memiliki traversalIndex
0, dan nilai jam 1 memiliki traversalIndex
1.
Dengan cara ini, urutan yang dibaca TalkBack akan ditetapkan. Sekarang, angka
dalam CircularLayout
dibaca dalam urutan yang diharapkan.
Karena traversalIndexes
yang telah ditetapkan hanya bersifat relatif terhadap indeks lain dalam pengelompokan yang sama, urutan layar lainnya telah dipertahankan. Dengan kata lain, perubahan semantik yang ditampilkan dalam cuplikan kode sebelumnya hanya mengubah pengurutan dalam tampilan jam yang telah menetapkan isTraversalGroup = true
.
Perhatikan bahwa, tanpa menetapkan semantik CircularLayout's
ke isTraversalGroup =
true
, perubahan traversalIndex
tetap berlaku. Namun, tanpa
CircularLayout
untuk mengikatnya, dua belas digit tampilan jam akan dibaca
terakhir, setelah semua elemen lain di layar telah dikunjungi. Hal ini terjadi
karena semua elemen lain memiliki traversalIndex
default 0f
, dan
elemen teks jam dibaca setelah semua elemen 0f
lainnya.
Contoh: Menyesuaikan urutan traversal untuk tombol tindakan mengambang
Dalam contoh ini, traversalIndex
dan isTraversalGroup
mengontrol
urutan traversal tombol tindakan mengambang (FAB) Desain Material. Dasar
dari contoh ini adalah tata letak berikut:
Secara default, tata letak dalam contoh ini memiliki urutan TalkBack berikut:
Panel Aplikasi Atas → Contoh teks 0 sampai 6 → tombol tindakan mengambang (FAB) → Panel Aplikasi Bawah
Anda mungkin ingin pembaca layar berfokus terlebih dahulu pada FAB. Untuk menetapkan
traversalIndex
pada elemen Material seperti FAB, lakukan hal berikut:
@Composable fun FloatingBox() { Box(modifier = Modifier.semantics { isTraversalGroup = true; traversalIndex = -1f }) { FloatingActionButton(onClick = {}) { Icon(imageVector = Icons.Default.Add, contentDescription = "fab icon") } } }
Dalam cuplikan ini, membuat kotak dengan
isTraversalGroup
yang ditetapkan ke true
dan menetapkan traversalIndex
di kotak yang sama
(-1f
lebih rendah dari nilai default 0f
) berarti kotak mengambang
akan muncul sebelum semua elemen lainnya di layar.
Selanjutnya, Anda dapat menempatkan kotak mengambang dan elemen lainnya ke dalam scaffold yang mengimplementasikan tata letak Desain Material:
@OptIn(ExperimentalMaterial3Api::class) @Composable fun ColumnWithFABFirstDemo() { Scaffold( topBar = { TopAppBar(title = { Text("Top App Bar") }) }, floatingActionButtonPosition = FabPosition.End, floatingActionButton = { FloatingBox() }, content = { padding -> ContentColumn(padding = padding) }, bottomBar = { BottomAppBar { Text("Bottom App Bar") } } ) }
TalkBack berinteraksi dengan elemen dalam urutan berikut:
FAB → Panel Aplikasi Atas → Contoh teks 0 sampai 6 → Panel Aplikasi Bawah
Referensi tambahan
- Aksesibilitas: Konsep dan teknik penting yang umum untuk semua pengembangan aplikasi Android
- Membuat Aplikasi yang Mudah Diakses: Langkah-langkah utama yang dapat Anda lakukan untuk membuat aplikasi lebih mudah diakses
- Prinsip-prinsip untuk meningkatkan aksesibilitas aplikasi: Prinsip utama yang harus diingat saat berupaya membuat aplikasi Anda lebih mudah diakses
- Menguji Aksesibilitas: Prinsip dan alat pengujian untuk aksesibilitas Android