Vlastní přístupný název místo automaticky odvozeného textu
Někdy viditelný text prvku (např. název s počtem v závorce) nezní, když ho čtečka přečte nahlas, přirozeně. Nebo možná chcete odečítači předat bohatší informaci, než kolik je vidět na obrazovce. Výchozí chování jednoduše přečte to, co je uvnitř. Pokud ale potřebujete text zcela nahradit, musíte použít Modifier.clearAndSetSemantics. Ten však zahodí sémantiku celého podstromu – včetně akce kliknutí, kterou by jinak modifier clickable automaticky zajistil.
1. Špatně — spoléhat na výchozí přečtení viditelného textu
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { onClick() }
.padding(horizontal = 16.dp, vertical = 14.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(icon, contentDescription = null)
Spacer(modifier = Modifier.width(16.dp))
Text("Všechny položky (42)")
}
TalkBack přečte přesně to, co je vidět — "Všechny položky, otevírající závorka, 42, zavírající závorka" (přesná podoba závisí na syntetizátoru), místo srozumitelné věty o počtu nepřečtených.
2. Správně — clearAndSetSemantics s vlastním popisem
@Composable
fun DashboardRow(icon: ImageVector, title: String, unreadCount: Int, focusRequester: FocusRequester, onClick: () -> Unit) {
val view = LocalView.current
val countText = if (unreadCount > 999) "999+" else unreadCount.toString()
val displayTitle = if (unreadCount > 0) "$title ($countText)" else title
val description = if (unreadCount > 0) "$title, $unreadCount nepřečtených" else "$title, vše přečteno"
Row(
modifier = Modifier.fillMaxWidth()
.focusRequester(focusRequester)
.clickable { view.clickSound(); onClick() }
.padding(horizontal = 16.dp, vertical = 14.dp)
.clearAndSetSemantics {
contentDescription = description
role = Role.Button
this.onClick { view.clickSound(); onClick(); true }
},
verticalAlignment = Alignment.CenterVertically
) {
Icon(icon, contentDescription = null, tint = MaterialTheme.colorScheme.primary)
Spacer(modifier = Modifier.width(16.dp))
Text(displayTitle, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.weight(1f))
}
}
clearAndSetSemantics zahodí sémantiku celého podstromu (včetně toho, co
by do ní jinak přispěl vnořený Text) a nahradí ji přesně tím, co je v
bloku. Proto description používá jiný, plynulejší tvar ("42 nepřečtených"
/ "vše přečteno") než viditelný text ("(42)") — čtečka ho nikdy nespojuje s
viditelným textem, jde o dvě úplně nezávislé věci.
3. Kde se to používá
V mé aplikaci pro čtení RSS kanálů tímhle způsobem funguje úplně každá položka na domovské obrazovce — "Všechny položky", "S hvězdičkou", každá složka i každý jednotlivý kanál. Viditelný text má počet v závorce, přístupný popis má plnou větu ("42 nepřečtených" / "vše přečteno").
Takový řádek je zároveň klikatelný, takže potřebuje i zvukovou odezvu na dotyk — viz Zvuk při tapnutí na interaktivní prvky (Jetpack Compose).
Proč to takhle je
clearAndSetSemanticszahazuje sémantiku VŠECH potomků, ne jen doplňuje — proto seTextuvnitř nikdy nepřečte souběžně sdescription. Kdyby se místo toho použil obyčejnýModifier.semantics { contentDescription = ... }(bez "clearAndSet"), TalkBack by přečetl obojí za sebou — vlastní popis i viditelný text znovu.role = Role.Buttonuvnitř bloku —clearAndSetSemanticszahodí i roli, kterou by řádek jinak mohl mít, takže je potřeba ji nastavit znovu, jinak TalkBack řádek neohlásí jako tlačítko.this.onClick { ... }uvnitř bloku — ze stejného důvodu:Modifier.clickablesám o sobě vystavuje do accessibility stromu i akci "kliknutí", aleclearAndSetSemanticsji zahodí spolu se vším ostatním. Bez ručního doplnění by dvojité poklepání v TalkBacku na řádku přestalo fungovat, i když by běžný dotyk (přesclickable) fungoval dál — proto seonClick()volá na obou místech, vclickablei uvnitřclearAndSetSemantics.- Přístupný popis a viditelný text se mohou lišit obsahem i formulací — nemusí to být to samé, jen jinak formátované; přístupná verze může nést informaci navíc (např. "vše přečteno" pro nulový počet, což viditelný text vůbec neřeší).
Pravidla
- WCAG 4.1.2 (Název, role, hodnota) — přístupný název, role tlačítka i (v tomto případě prostřednictvím textu) stav musí být programově zjistitelné jako jeden konzistentní celek.
Shrnutí: Modifier.clearAndSetSemantics { contentDescription = ...; role = Role.Button; onClick {...} } úplně nahradí, co čtečka o prvku řekne —
včetně role a akce kliknutí, které by jinak zajistil clickable. Používá
se, když má přístupný popis nést jiné/bohatší informace než holý viditelný
text, a je potřeba zabránit tomu, aby se ten viditelný text ještě přečetl
navíc.
Komentáře
Zatím zde nejsou žádné komentáře. Buďte první, kdo napíše svůj názor.
Přidat komentář k „Vlastní přístupný název místo automaticky odvozeného textu“