Mentre i servizi di accessibilità navigano tra gli elementi sullo schermo, è importante che questi elementi siano raggruppati, separati o persino nascosti con la granularità corretta. Quando ogni singolo componibile di basso livello sullo schermo viene evidenziato in modo indipendente, gli utenti devono interagire molto per spostarsi sullo schermo. Se gli elementi si uniscono in modo troppo aggressivo, gli utenti potrebbero non capire quali elementi appartengono logicamente insieme. Se sullo schermo sono presenti elementi puramente decorativi, questi potrebbero essere nascosti ai servizi di accessibilità. In questi casi, puoi utilizzare le API di Compose per unire, cancellare e nascondere la semantica.
Unisci semantica
Quando applichi un modificatore clickable a un componibile principale, Compose unisce automaticamente tutti gli elementi secondari al suo interno. Per capire in che modo i componenti interattivi di Compose Material e Foundation utilizzano le strategie di unione per impostazione predefinita, consulta la sezione Elementi interattivi.
È comune che un componente sia costituito da più componibili. Questi componibili potrebbero formare un gruppo logico e ciascuno potrebbe contenere informazioni importanti, ma potresti comunque voler che i servizi di accessibilità li visualizzino come un unico elemento.
Ad esempio, pensa a un composable che mostra l'avatar di un utente, il suo nome e alcune informazioni aggiuntive:
Puoi attivare Compose per unire questi elementi utilizzando il parametro mergeDescendants nel modificatore di semantica. In questo modo, i servizi di accessibilità trattano il componente come un'unica entità e tutte le proprietà semantiche dei discendenti vengono unite:
@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") } } }
I servizi di accessibilità ora si concentrano sull'intero container contemporaneamente e ne uniscono i contenuti:
Ogni proprietà di semantica ha una strategia di unione definita. Ad esempio, la proprietà ContentDescription aggiunge tutti i valori ContentDescription discendenti a un elenco. Puoi controllare la strategia di unione di una proprietà di semantica controllando la sua implementazione mergePolicy in SemanticsProperties.kt.
Le proprietà possono assumere il valore principale o secondario, unire i valori in un elenco o in una stringa, non consentire l'unione e generare un'eccezione o qualsiasi altra strategia di unione personalizzata.
Esistono altri scenari in cui ti aspetti che la semantica secondaria venga unita a quella principale, ma ciò non accade. Nell'esempio seguente, abbiamo un elemento principale dell'elenco clickable con elementi secondari e potremmo aspettarci che l'elemento principale li unisca tutti:
@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) } }
Quando l'utente preme l'elemento clickable Row, l'articolo si apre. All'interno è presente un BookmarkButton per aggiungere l'articolo ai preferiti. Questo pulsante nidificato viene visualizzato come non unito, mentre il resto dei contenuti secondari all'interno della riga è unito:
Row. L'albero non unito contiene nodi separati per ogni Text composableAlcuni elementi componibili non vengono uniti automaticamente in un elemento principale, per impostazione predefinita. Un elemento principale non può unire i suoi elementi secondari quando anche questi ultimi vengono uniti, sia impostando esplicitamente mergeDescendants = true sia essendo componenti che si uniscono, come pulsanti o elementi cliccabili. Sapere come determinate API si uniscono o non si uniscono può aiutarti a eseguire il debug di alcuni comportamenti potenzialmente imprevisti.
Utilizza l'unione quando gli elementi secondari costituiscono un gruppo logico e sensato
all'interno dell'elemento principale. Tuttavia, se gli elementi secondari nidificati richiedono la regolazione manuale o la rimozione della propria semantica, altre API potrebbero essere più adatte alle tue esigenze (ad esempio, clearAndSetSemantics).
Cancella e imposta la semantica
Se le informazioni semantiche devono essere completamente cancellate o sovrascritte, un'API efficace da utilizzare è clearAndSetSemantics.
Quando è necessario cancellare la semantica di un componente e dei suoi discendenti, utilizza questa API con una funzione lambda vuota. Quando la semantica deve essere sovrascritta, includi i nuovi contenuti all'interno della funzione lambda.
Tieni presente che, quando esegui la cancellazione con una lambda vuota, la semantica cancellata non viene inviata a nessun consumer che utilizza queste informazioni, come l'accessibilità, la compilazione automatica o i test. Quando sovrascrivi i contenuti con
clearAndSetSemantics{/*semantic information*/}, la nuova semantica sostituisce tutta
la semantica precedente dell'elemento e dei relativi discendenti.
Di seguito è riportato un esempio di un componente di attivazione/disattivazione personalizzato, rappresentato da una riga interattiva con un'icona e un testo:
// 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?") } }
Sebbene l'icona e il testo contengano alcune informazioni semantiche, insieme non indicano che questo componente è attivabile/disattivabile. L'unione non è sufficiente perché devi fornire informazioni aggiuntive sul componente.
Poiché lo snippet riportato sopra crea un componente di attivazione/disattivazione personalizzato, devi aggiungere
la funzionalità di attivazione/disattivazione, nonché la semantica stateDescription,
toggleableState e role. In questo modo, lo stato del componente e l'azione associata sono disponibili. Ad esempio, TalkBack annuncia "Tocca due volte per attivare/disattivare" anziché "Tocca due volte per attivare".
Cancellando la semantica originale e impostandone una nuova e più descrittiva, i servizi di accessibilità possono ora vedere che si tratta di un componente attivabile/disattivabile che può alternare lo stato.
Quando utilizzi clearAndSetSemantics, tieni presente quanto segue:
- Poiché i servizi non ricevono informazioni quando questa API è impostata, è meglio utilizzarla con parsimonia.
- Le informazioni semantiche possono essere utilizzate da agenti AI e servizi simili per comprendere lo schermo, pertanto devono essere cancellate solo se necessario.
- La semantica personalizzata può essere impostata all'interno della funzione lambda dell'API.
- L'ordine dei modificatori è importante: questa API cancella tutta la semantica che si trova dopo il punto in cui viene applicata, indipendentemente dalle altre strategie di unione.
Nascondi semantica
In alcuni scenari, non è necessario inviare elementi ai servizi di accessibilità, ad esempio se le informazioni aggiuntive sono ridondanti per l'accessibilità o se sono puramente decorative e non interattive. In questi casi, puoi nascondere gli elementi con l'API hideFromAccessibility.
Negli esempi seguenti sono riportati i componenti che potrebbe essere necessario nascondere: una filigrana ridondante che si estende su un componente e un carattere utilizzato per separare le informazioni in modo decorativo.
@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 •" ) }
L'utilizzo di hideFromAccessibility qui garantisce che la filigrana e la decorazione siano nascoste ai servizi di accessibilità, ma mantengano comunque la loro semantica per altri casi d'uso, come i test.
Suddivisione dei casi d'uso
Di seguito è riportato un riepilogo dei casi d'uso per capire come distinguere chiaramente le API precedenti:
- Quando i contenuti non sono destinati a essere utilizzati dai servizi di accessibilità:
- Utilizza
hideFromAccessibilityquando i contenuti sono probabilmente decorativi o ridondanti, ma devono comunque essere testati. - Utilizza
clearAndSetSemantics{}con una funzione lambda vuota quando la semantica principale e secondaria deve essere cancellata per tutti i servizi. - Utilizza
clearAndSetSemantics{/*content*/}con i contenuti all'interno della funzione lambda quando la semantica di un componente deve essere impostata manualmente.
- Utilizza
- Quando i contenuti devono essere trattati come un'unica entità e richiedono tutte le informazioni delle entità secondarie per essere completi:
- Utilizza l'unione dei discendenti semantici.
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Accessibilità in Compose
- [Material Design 2 in Compose][19]
- Test del layout di Compose