Domyślnie działanie czytnika ekranu w aplikacji do tworzenia wiadomości odbywa się w oczekiwanej kolejności czytania – zazwyczaj od lewej do prawej, a następnie z góry do dołu.
W niektórych typach układów aplikacji algorytm nie może jednak określić rzeczywistej kolejności czytania bez dodatkowych wskazówek. W aplikacjach z widokiem danych możesz rozwiązać takie problemy, korzystając z właściwości traversalBefore
i traversalAfter
.
Począwszy od tworzenia wersji 1.5 funkcja Compose udostępnia równie elastyczny interfejs API, ale z nowym modelem koncepcyjnym.
isTraversalGroup
i traversalIndex
to właściwości semantyczne, które umożliwiają kontrolowanie ułatwień dostępu i kolejności zaznaczenia w TalkBack w sytuacjach, gdy domyślny algorytm sortowania jest nieodpowiedni. isTraversalGroup
identyfikuje grupy ważne semantycznie, a traversalIndex
dostosowuje kolejność poszczególnych elementów w tych grupach. Możesz użyć samej listy isTraversalGroup
lub traversalIndex
, aby dodatkowo dostosować działanie.
Użyj isTraversalGroup
i traversalIndex
w aplikacji, aby kontrolować kolejność przechodzenia między czytnikami ekranu.
Grupuj elementy za pomocą funkcji isTraversalGroup
isTraversalGroup
to właściwość wartości logicznej, która określa, czy węzeł semantyka jest grupą przemierzania. Węzeł tego typu służy jako granica przy organizowaniu elementów podrzędnych węzła.
Ustawienie isTraversalGroup = true
w węźle oznacza, że wszystkie jego elementy podrzędne są odwiedzane przed przejściem do innych elementów. Możesz ustawić isTraversalGroup
w węzłach, które nie można zaznaczyć, przy użyciu czytnika ekranu, takich jak kolumny, wiersze lub pola.
W poniższym przykładzie użyto parametru isTraversalGroup
. Emituje on 4 elementy tekstowe. Dwa lewe elementy należą do 1 elementu CardBox
, a 2 po prawej – do kolejnego elementu 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 ) } }
Kod wygeneruje dane wyjściowe podobne do tych:
Ponieważ nie ustawiono żadnej semantyki, czytnik ekranu domyślnie porusza się między elementami od lewej do prawej i z góry na dół. Ze względu na to ustawienie domyślne TalkBack odczytuje fragmenty zdań w niewłaściwej kolejności:
„To zdanie znajduje się w” → „To zdanie to” → „w lewej kolumnie”. → „po prawej”.
Aby prawidłowo uporządkować fragmenty, zmień oryginalny fragment kodu, ustawiając parametr isTraversalGroup
na 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 } ) } }
Ponieważ atrybut isTraversalGroup
jest ustawiony specjalnie dla każdego elementu CardBox
, podczas sortowania jego elementów obowiązują granice CardBox
. W tym przypadku jako pierwszy odczytywany jest tekst CardBox
, a po nim prawy CardBox
.
Teraz TalkBack odczytuje fragmenty zdań we właściwej kolejności:
„To zdanie znajduje się w” → „lewej kolumnie”. → „To zdanie to” → „po prawej”.
Dostosuj kolejność przechodzenia
traversalIndex
to właściwość liczby zmiennoprzecinkowej, która umożliwia dostosowywanie kolejności przechodzenia między elementami TalkBack. Jeśli grupowanie elementów nie wystarcza do prawidłowego działania TalkBack,
użyj funkcji traversalIndex
w połączeniu z atrybutem isTraversalGroup
, by jeszcze bardziej dostosować kolejność czytników ekranu.
Właściwość traversalIndex
ma te cechy:
- Elementy o niższych wartościach
traversalIndex
mają wyższy priorytet. - Może być dodatni lub ujemny.
- Wartość domyślna to
0f
. - Ma wpływ tylko na węzły, do których można przejść w czytniku ekranu, takie jak elementy ekranowe takie jak tekst czy przyciski. Na przykład ustawienie w kolumnie tylko wartości
traversalIndex
nie przyniesie żadnego efektu, chyba że w kolumnie też zostanie ustawiony parametrisTraversalGroup
.
Ten przykład ilustruje, jak można używać jednocześnie atrybutów traversalIndex
i isTraversalGroup
.
Przykład: Przesuwanie tarczy zegara
Tarcza zegara to typowy scenariusz, w którym nie działa standardowa kolejność przechodzenia między elementami. Przykład w tej sekcji to selektor godziny, w którym użytkownik może przeglądać liczby na tarczy zegara i wybierać cyfry dla przedziałów godzin i minut.
W tym uproszczonym fragmencie znajduje się CircularLayout
, w którym narysowanych zostanie 12 liczb, zaczynając od 12 i poruszając się w prawo po okręgu:
@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()) } }
Ponieważ tarcza zegara nie jest logicznie odczytywana przy domyślnej kolejności od lewej do prawej i od góry do dołu, TalkBack odczytuje liczby w niewłaściwej kolejności. Aby to skorygować, użyj przyrostowej wartości licznika, jak w tym fragmencie:
@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()) } }
Aby poprawnie ustawić kolejność przechodzenia między elementami, najpierw utwórz grupę przemierzania CircularLayout
i ustaw element isTraversalGroup = true
. Następnie, gdy każdy tekst zegara jest rysowany w układzie, ustaw odpowiadający mu tekst traversalIndex
na wartość licznika.
Ponieważ wartość licznika stale rośnie, każda wartość zegara
traversalIndex
zwiększa się w miarę dodawania liczb na ekranie — wartość zegara 0
ma traversalIndex
wartość 0, a wartość zegara 1 ma wartość traversalIndex
równy 1.
Dzięki temu zostanie ustalona kolejność ich odczytywania przez TalkBack. Teraz liczby w elemencie CircularLayout
są odczytywane w oczekiwanej kolejności.
Ustawione elementy traversalIndexes
są powiązane tylko z innymi indeksami w tej samej grupie, więc pozostała część kolejności ekranu została zachowana. Oznacza to, że zmiany semantyczne widoczne w poprzednim fragmencie kodu modyfikują tylko tę kolejność w obrębie tarczy zegara, która ma ustawioną wartość isTraversalGroup = true
.
Pamiętaj, że jeśli nie ustawisz semantyki CircularLayout's
na isTraversalGroup =
true
, zmiany traversalIndex
nadal będą obowiązywać. Jeśli jednak nie da się ich powiązać za pomocą CircularLayout
, 12 cyfr na tarczy zegara jest odczytywanych na końcu, gdy wszystkie pozostałe elementy na ekranie zostały wyświetlone. Dzieje się tak dlatego, że wszystkie pozostałe elementy mają domyślną wartość traversalIndex
wynoszącą 0f
, a teksty zegara są odczytywane po wszystkich pozostałych elementach 0f
.
Przykład: dostosowywanie kolejności przechodzenia w przypadku pływającego przycisku polecenia
W tym przykładzie elementy traversalIndex
i isTraversalGroup
określają kolejność przechodzenia pomiędzy elementami pływającego przycisku polecenia Material Design (FAB). Podstawą tego przykładu jest taki układ:
Domyślnie układ w tym przykładzie ma taką kolejność TalkBack:
Górny pasek aplikacji → Przykładowe teksty 0–6 → pływający przycisk polecenia (FAB) → Dolny pasek aplikacji
Czytnik ekranu może najpierw skupić się na przycisku typu FAB. Aby ustawić traversalIndex
w elemencie Material, takim jak przycisk typu FAB, wykonaj te czynności:
@Composable fun FloatingBox() { Box(modifier = Modifier.semantics { isTraversalGroup = true; traversalIndex = -1f }) { FloatingActionButton(onClick = {}) { Icon(imageVector = Icons.Default.Add, contentDescription = "fab icon") } } }
W tym fragmencie kodu utworzenie pola z parametrem isTraversalGroup
ustawionym na true
i ustawieniem w tym samym polu elementu traversalIndex
(wartość -1f
jest niższa niż wartość domyślna 0f
) oznacza, że pole pływające będzie wyświetlać się przed wszystkimi innymi elementami ekranowymi.
Następnie możesz umieścić pływające pole i inne elementy w rusztowaniu, które stosuje układ 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 współdziała z elementami w następującej kolejności:
FAB → Górny pasek aplikacji → Przykładowe teksty 0–6 → Dolny pasek aplikacji
Dodatkowe materiały
- Ułatwienia dostępu: podstawowe pojęcia i techniki, które są wspólne dla wszystkich tworzenia aplikacji na Androida.
- Tworzenie dostępnych aplikacji: kluczowe czynności, które możesz podjąć, aby zwiększyć dostępność aplikacji.
- Zasady dotyczące ułatwień dostępu do aplikacji: kluczowe zasady, o których warto pamiętać, tworząc ułatwienia dostępu w aplikacji.
- Testowanie pod kątem ułatwień dostępu: testowanie zasad i narzędzi ułatwień dostępu na Androidzie.