Per aiutare le persone con esigenze di accessibilità a usare correttamente la tua app, progetta la tua per supportare i principali requisiti di accessibilità.
Valutare le dimensioni minime dei touch target
Ogni elemento visualizzato sullo schermo che è possibile selezionare, toccare o con cui è possibile interagire deve abbastanza grande da consentire un'interazione affidabile. Quando scegli le dimensioni di questi elementi, assicurati di imposta le dimensioni minime su 48 dp per rispettare correttamente il Material Design linee guida sull'accessibilità.
Componenti dei materiali, come Checkbox
, RadioButton
, Switch
,
Slider
e Surface
: imposta internamente questa dimensione minima, ma solo
quando il componente può ricevere azioni dell'utente. Ad esempio, quando Checkbox
ha
il parametro onCheckedChange
è impostato su un valore diverso da null, la casella di controllo include
per avere una larghezza e un'altezza di almeno 48 dp.
@Composable private fun CheckableCheckbox() { Checkbox(checked = true, onCheckedChange = {}) }
Se il parametro onCheckedChange
è impostato su null, la spaziatura interna non è
perché non è possibile interagire direttamente con il componente.
@Composable private fun NonClickableCheckbox() { Checkbox(checked = true, onCheckedChange = null) }
Quando implementi controlli di selezione come Switch
, RadioButton
o
Checkbox
, in genere rimuovi il comportamento cliccabile a un contenitore principale, imposta
il callback clic sul componibile in null
e aggiungi toggleable
selectable
al componibile principale.
@Composable private fun CheckableRow() { MaterialTheme { var checked by remember { mutableStateOf(false) } Row( Modifier .toggleable( value = checked, role = Role.Checkbox, onValueChange = { checked = !checked } ) .padding(16.dp) .fillMaxWidth() ) { Text("Option", Modifier.weight(1f)) Checkbox(checked = checked, onCheckedChange = null) } } }
Quando le dimensioni di un componibile cliccabile sono inferiori al touch target minimo , Compose aumenta comunque le dimensioni del touch target. per farlo espandendo le dimensioni del touch target al di fuori dei confini del componibile.
Il seguente esempio contiene un elemento Box
cliccabile molto piccolo. Il touch target
si espande automaticamente oltre i confini di Box
, quindi toccare
accanto a Box
attiva comunque l'evento di clic.
@Composable private fun SmallBox() { var clicked by remember { mutableStateOf(false) } Box( Modifier .size(100.dp) .background(if (clicked) Color.DarkGray else Color.LightGray) ) { Box( Modifier .align(Alignment.Center) .clickable { clicked = !clicked } .background(Color.Black) .size(1.dp) ) } }
Per evitare possibili sovrapposizioni tra aree di tocco di diversi componibili,
utilizzare una dimensione minima sufficientemente grande per il componibile. Nell'esempio,
significa utilizzare il tasto di modifica sizeIn
per impostare la dimensione minima per la scatola interna:
@Composable private fun LargeBox() { var clicked by remember { mutableStateOf(false) } Box( Modifier .size(100.dp) .background(if (clicked) Color.DarkGray else Color.LightGray) ) { Box( Modifier .align(Alignment.Center) .clickable { clicked = !clicked } .background(Color.Black) .sizeIn(minWidth = 48.dp, minHeight = 48.dp) ) } }
Aggiungi etichette clic
Puoi utilizzare un'etichetta clic per aggiungere un significato semantico al comportamento del clic di un componibili. Le etichette clic descrivono cosa succede quando l'utente interagisce con il componibili. I servizi di accessibilità usano le etichette clic per descrivere l'app a: utenti con esigenze specifiche.
Imposta l'etichetta clic trasmettendo un parametro nel modificatore clickable
:
@Composable private fun ArticleListItem(openArticle: () -> Unit) { Row( Modifier.clickable( // R.string.action_read_article = "read article" onClickLabel = stringResource(R.string.action_read_article), onClick = openArticle ) ) { // .. } }
In alternativa, se non hai accesso al tasto di modifica cliccabile, imposta l'etichetta clic nel modificatore semantics:
@Composable private fun LowLevelClickLabel(openArticle: () -> Boolean) { // R.string.action_read_article = "read article" val readArticleLabel = stringResource(R.string.action_read_article) Canvas( Modifier.semantics { onClick(label = readArticleLabel, action = openArticle) } ) { // .. } }
Descrivere gli elementi visivi
Quando definisci un componibile Image
o Icon
, non esiste
modo automatico al framework Android di capire cos'è
visualizzazione. Devi trasmettere una descrizione testuale dell'elemento visivo.
Immagina una schermata in cui l'utente può condividere la pagina corrente con gli amici. Questo schermo contiene un'icona di condivisione cliccabile:
Basandosi solo sull'icona, il framework Android non è in grado di descriverla a un con disabilità uditiva. Il framework Android richiede un'ulteriore descrizione testuale l'icona.
Il parametro contentDescription
descrive un elemento visivo. Utilizza un
perché è visibile all'utente.
@Composable private fun ShareButton(onClick: () -> Unit) { IconButton(onClick = onClick) { Icon( imageVector = Icons.Filled.Share, contentDescription = stringResource(R.string.label_share) ) } }
Alcuni elementi visivi sono puramente decorativi e potresti non voler comunicare
per l'utente. Se imposti il parametro contentDescription
su null
,
indicare al framework Android che questo elemento non è associato
azioni o lo stato desiderato.
@Composable private fun PostImage(post: Post, modifier: Modifier = Modifier) { val image = post.imageThumb ?: painterResource(R.drawable.placeholder_1_1) Image( painter = image, // Specify that this image has no semantic meaning contentDescription = null, modifier = modifier .size(40.dp, 40.dp) .clip(MaterialTheme.shapes.small) ) }
Sei tu a decidere se un determinato elemento visivo necessita di un
contentDescription
. Chiediti se l'elemento trasmette informazioni che
l'utente dovrà eseguire la propria attività. In caso contrario, è preferibile lasciare la
descrizione.
Unisci elementi
I servizi di accessibilità come TalkBack e Switch Access consentono agli utenti di spostare lo stato attivo tra gli elementi sullo schermo. È importante che gli elementi siano incentrati livello di dettaglio corretto. Quando ogni singolo elemento componibile di basso livello sul tuo schermo viene e 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 quale che gli elementi appartengano
Quando applichi un modificatore clickable
a un componibile, Compose
unisce automaticamente tutti gli elementi contenuti nel componibile. Questo vale anche per
ListItem
l'unione degli elementi di un elemento dell'elenco e l'accessibilità
e servizi li vedono come un unico elemento.
È possibile avere un insieme di componenti componibili che formano un gruppo logico, ma gruppo non cliccabile o parte di un elemento dell'elenco. Vuoi continuare a usare l'accessibilità per visualizzarli come un unico elemento. Ad esempio, immagina un componibile mostra l'avatar di un utente, il suo nome e alcune informazioni aggiuntive:
Puoi consentire a Compose di unire questi elementi utilizzando l'mergeDescendants
nel modificatore semantics
. In questo modo, i servizi di accessibilità
selezionare solo l'elemento unito e tutte le proprietà semantiche dei discendenti
vengono uniti.
@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, unendoli i relativi contenuti:
Aggiungi azioni personalizzate
Dai un'occhiata al seguente elemento dell'elenco:
Quando utilizzi uno screen reader come TalkBack per ascoltare ciò che viene visualizzato nella schermata iniziale, viene selezionato prima l'intero elemento e poi l'icona dei preferiti.
In un elenco lungo, questo può diventare molto ripetitivo. Un approccio migliore consiste nel
definisci un'azione personalizzata che consenta a un utente di aggiungere l'elemento ai preferiti. Aspetti da tenere presenti
che devi anche rimuovere esplicitamente il comportamento dell'icona dei preferiti
per assicurarsi che non sia selezionato dal servizio di accessibilità. Questo
si ottiene utilizzando il tasto di modifica clearAndSetSemantics
:
@Composable private fun PostCardSimple( /* ... */ isFavorite: Boolean, onToggleFavorite: () -> Boolean ) { val actionLabel = stringResource( if (isFavorite) R.string.unfavorite else R.string.favorite ) Row( modifier = Modifier .clickable(onClick = { /* ... */ }) .semantics { // Set any explicit semantic properties customActions = listOf( CustomAccessibilityAction(actionLabel, onToggleFavorite) ) } ) { /* ... */ BookmarkButton( isBookmarked = isFavorite, onClick = onToggleFavorite, // Clear any semantics properties set on this node modifier = Modifier.clearAndSetSemantics { } ) } }
Descrivere lo stato di un elemento
Un componibile può definire una stateDescription
per la semantica,
Il framework Android utilizza per leggere lo stato in cui si trova il componibile. Per
Ad esempio, un componibile attivabile può essere sia in formato "selezionato" o "deselezionata"
stato. In alcuni casi, potresti voler sostituire la descrizione dello stato predefinita
utilizzate da Compose. Puoi farlo specificando esplicitamente lo stato
prima di definire un componibile come attivabile:
@Composable private fun TopicItem(itemTitle: String, selected: Boolean, onToggle: () -> Unit) { val stateSubscribed = stringResource(R.string.subscribed) val stateNotSubscribed = stringResource(R.string.not_subscribed) Row( modifier = Modifier .semantics { // Set any explicit semantic properties stateDescription = if (selected) stateSubscribed else stateNotSubscribed } .toggleable( value = selected, onValueChange = { onToggle() } ) ) { /* ... */ } }
Definisci intestazioni
A volte le app mostrano molti contenuti su una sola schermata in un contenitore scorrevole. Ad esempio, una schermata potrebbe mostrare l'intero contenuto di un articolo che l'utente sta leggendo:
Gli utenti con esigenze di accessibilità hanno difficoltà a navigare in una schermata di questo tipo. Per aiutare di navigazione, indica quali elementi sono intestazioni. Nell'esempio precedente, ogni può essere definito come intestazione per l'accessibilità. Alcune come TalkBack, consentono agli utenti di navigare direttamente in heading.
In Compose, indichi che un componibile è un'intestazione definendone il
Proprietà semantics
:
@Composable private fun Subsection(text: String) { Text( text = text, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.semantics { heading() } ) }
Gestire elementi componibili personalizzati
Ogni volta che sostituisci determinati componenti Material nella tua app con devi tenere presenti le considerazioni sull'accessibilità.
Supponiamo che tu stia sostituendo il materiale Checkbox
con la tua implementazione.
Potresti dimenticare di aggiungere il modificatore triStateToggleable
, che gestisce
le proprietà di accessibilità per questo componente.
Come regola generale, considera l'implementazione del componente in la libreria Material e imitare qualsiasi comportamento di accessibilità che riesci a trovare. Inoltre, fai un uso intensivo dei modificatori di base, anziché a livello di UI che includono considerazioni sull'accessibilità pronte all'uso.
Testa l'implementazione del componente personalizzato con più dei servizi di accessibilità per verificarne il comportamento.
Risorse aggiuntive
- Accessibilità: concetti essenziali e tecniche comuni a tutti gli sviluppatori di app per Android
- Creare app accessibili: passaggi chiave che puoi svolgere per rendere la tua app più accessibile
- Principi per il miglioramento delle app accessibilità: principi chiave per tieni presente quando lavori per rendere la tua app più accessibile
- Test per l'accessibilità: Principi e strumenti di test per l'accessibilità Android