Per impostazione predefinita, viene implementato il comportamento dello screen reader di accessibilità in un'app Compose
nell'ordine di lettura previsto, che solitamente è da sinistra a destra e poi dall'alto verso il basso.
Tuttavia, esistono alcuni tipi di layout delle app in cui l'algoritmo non può determinare
l'ordine di lettura effettivo senza ulteriori suggerimenti. Nelle app basate sulle visualizzazioni, puoi:
risolvi questi problemi usando le proprietà traversalBefore
e traversalAfter
.
A partire da Compose 1.5, Compose offre un'API altrettanto flessibile, ma con
un nuovo modello concettuale.
isTraversalGroup
e traversalIndex
sono proprietà semantiche che
consentono di controllare l'accessibilità e l'ordine di messa a fuoco di TalkBack negli scenari in cui
l'algoritmo di ordinamento predefinito non è appropriato. isTraversalGroup
identifica
importanti dal punto di vista semantico, mentre traversalIndex
regola l'ordine
i singoli elementi all'interno di questi gruppi. Puoi usare isTraversalGroup
da solo,
o con traversalIndex
per un'ulteriore personalizzazione.
Utilizza isTraversalGroup
e traversalIndex
in
per controllare l'ordine di attraversamento dello screen reader.
Raggruppa gli elementi con isTraversalGroup
isTraversalGroup
è una proprietà booleana che definisce se una semantica
Node è un gruppo di attraversamento. Questo tipo di nodo è quello la cui funzione è servire
come confine nell'organizzazione degli elementi secondari del nodo.
L'impostazione di isTraversalGroup = true
su un nodo significa che tutti i relativi figli
vengono visitate prima di passare ad altri elementi. Puoi impostare isTraversalGroup
su
nodi non attivabili per gli screen reader, come Colonne, Righe o Riquadri.
L'esempio seguente utilizza isTraversalGroup
. Emette quattro elementi di testo. La
i due elementi a sinistra appartengono a un elemento CardBox
, mentre i due elementi a destra
appartengono a un altro elemento CardBox
:
// 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 ) } }
Il codice produce un output simile al seguente:
Poiché non è stata impostata alcuna semantica, il comportamento predefinito dello screen reader è per attraversare gli elementi da sinistra a destra e dall'alto verso il basso. Per questo motivo per impostazione predefinita, TalkBack legge i frammenti della frase nell'ordine sbagliato:
"Questa frase è in" → "Questa frase è" → "la colonna a sinistra." → "sul a destra".
Per ordinare correttamente i frammenti, modifica lo snippet originale in modo da impostare
Da isTraversalGroup
a 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 } ) } }
Poiché il valore isTraversalGroup
viene impostato specificamente su ogni CardBox
, il valore di CardBox
i confini vengono applicati
durante l'ordinamento degli elementi. In questo caso, il riquadro a sinistra
Viene letto per primo CardBox
, seguito da CardBox
a destra.
A questo punto, TalkBack legge i frammenti della frase nell'ordine corretto:
"Questa frase è in" → "la colonna a sinistra." → "Questa frase è" → "sul a destra".
Personalizzare ulteriormente l'ordine di attraversamento
traversalIndex
è una proprietà mobile che ti consente di personalizzare TalkBack
ordine di attraversamento. Se raggruppare gli elementi non è sufficiente per consentire a TalkBack
funzionare correttamente, usa traversalIndex
insieme a
isTraversalGroup
per personalizzare ulteriormente l'ordine dello screen reader.
La proprietà traversalIndex
ha le seguenti caratteristiche:
- Gli elementi con valori
traversalIndex
più bassi hanno la priorità per primi. - Può essere positivo o negativo.
- Il valore predefinito è
0f
. - Interessa solo i nodi attivabili per lo screen reader, come gli elementi sullo schermo come
testo o pulsanti. Ad esempio, se imposti solo
traversalIndex
in una colonna, non hanno effetto, a meno che sulla colonna non sia impostato anche il valoreisTraversalGroup
.
L'esempio seguente mostra come utilizzare traversalIndex
e
isTraversalGroup
insieme.
Esempio: spostamento quadrante orologio
Un quadrante orologio è uno scenario comune in cui l'ordine di attraversamento standard non al lavoro. L'esempio in questa sezione è un selettore di orario, in cui un utente può attraverso i numeri su un quadrante orologio e seleziona le cifre per l'ora e i minuti slot machine.
Nel seguente snippet semplificato è presente un elemento CircularLayout
in cui 12
vengono tracciati numeri che iniziano con 12 e si spostano in senso orario intorno al cerchio:
@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()) } }
Poiché il quadrante orologio non viene letto logicamente con i valori predefiniti da sinistra a destra e dall'alto verso il basso, TalkBack legge i numeri in ordine non corretto. Per rettificare utilizza il valore incrementale del contatore, come mostrato nello snippet seguente:
@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()) } }
Per impostare correttamente l'ordine di attraversamento, per prima cosa imposta CircularLayout
come
gruppo di attraversamento e imposta isTraversalGroup = true
. Poi, poiché il testo di ogni orologio viene
disegnato sul layout, imposta il valore traversalIndex
corrispondente sul contatore
valore.
Dato che il valore del contatore aumenta continuamente, il valore di ogni orologio
traversalIndex
è maggiore quando vengono aggiunti numeri allo schermo: il valore dell'orologio è 0
ha un traversalIndex
pari a 0 e il valore dell'orologio 1 ha un traversalIndex
di 1.
In questo modo, viene impostato l'ordine in cui TalkBack le legge. I numeri
all'interno di CircularLayout
vengono letti nell'ordine previsto.
Poiché i traversalIndexes
che sono stati impostati sono relativi solo ad altri
indici all'interno dello stesso raggruppamento, il resto dell'ordinamento delle schermate è
vengono conservati. In altre parole, la semantica mostrata nel codice precedente
modificare solo l'ordine all'interno del quadrante orologio che ha
isTraversalGroup = true
impostato.
Tieni presente che, senza impostare la semantica di CircularLayout's
su isTraversalGroup =
true
, le modifiche relative a traversalIndex
continuano a essere applicate. Tuttavia, senza
CircularLayout
per associarli, vengono lette le dodici cifre del quadrante orologio
dopo aver visitato
tutti gli altri elementi sullo schermo. Ciò si verifica
perché tutti gli altri elementi hanno un valore predefinito per traversalIndex
di 0f
, mentre
gli elementi di testo dell'orologio vengono letti dopo tutti gli altri elementi 0f
.
Esempio: personalizza l'ordine di attraversamento per il pulsante di azione mobile
In questo esempio, traversalIndex
e isTraversalGroup
controllano il
ordine di attraversamento di un pulsante di azione mobile (FAB) di Material Design. Le basi
di questo esempio è il seguente layout:
Per impostazione predefinita, il layout in questo esempio ha il seguente ordine di TalkBack:
Barra delle app in alto → Testi di esempio da 0 a 6 → pulsante di azione mobile (FAB) → In basso Barra delle app
Potresti volere che lo screen reader si concentri innanzitutto sul FAB. Per impostare un
traversalIndex
su un elemento Material, ad esempio un FAB:
@Composable fun FloatingBox() { Box(modifier = Modifier.semantics { isTraversalGroup = true; traversalIndex = -1f }) { FloatingActionButton(onClick = {}) { Icon(imageVector = Icons.Default.Add, contentDescription = "fab icon") } } }
In questo snippet, la creazione di un riquadro
isTraversalGroup
impostata su true
e con traversalIndex
nella stessa casella
(-1f
è inferiore al valore predefinito di 0f
) significa che la casella mobile
viene prima di tutti gli altri elementi sullo schermo.
Successivamente, puoi inserire la scatola mobile e altri elementi in uno scaffold, implementa un layout Material Design:
@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 interagisce con gli elementi nel seguente ordine:
FAB → Barra delle app in alto → Testi di esempio da 0 a 6 → Barra delle app in basso
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