Domyślnie zaimplementowane jest działanie czytnika ekranu ułatwień dostępu w aplikacji Compose
w oczekiwanej kolejności czytania, czyli zwykle od lewej do prawej, a potem od góry do dołu.
Istnieją jednak typy układów aplikacji, w których algorytm nie jest w stanie określić,
w rzeczywistości, bez dodatkowych wskazówek. W aplikacjach opartych na widokach możesz:
rozwiąż takie problemy za pomocą właściwości traversalBefore
i traversalAfter
.
Od wersji Compose 1.5 dostępna jest równie elastyczny interfejs API, ale
nowym modelem koncepcyjnym.
isTraversalGroup
i traversalIndex
to właściwości semantyczne, które
umożliwiają sterowanie ułatwieniami dostępu i kolejności zaznaczenia w TalkBack
domyślny algorytm sortowania jest nieodpowiedni. isTraversalGroup
identyfikuje
grup o znaczeniu semantycznym, natomiast traversalIndex
dostosowuje kolejność
poszczególnych elementów w tych grupach. Możesz używać tylko nazwy isTraversalGroup
,
lub za pomocą traversalIndex
, aby
dostosować je do własnych potrzeb.
Korzystaj z usług isTraversalGroup
i traversalIndex
w
do sterowania kolejnością przechodzenia między czytnikami ekranu.
Grupuj elementy za pomocą funkcji isTraversalGroup
isTraversalGroup
to właściwość logiczna, która określa, czy semantyka
węzeł to grupa przemierzania. Ten typ węzła to węzeł, którego funkcja ma służyć
jako granicę lub obramowania przy organizacji elementów podrzędnych węzła.
Ustawienie isTraversalGroup = true
w węźle oznacza, że wszystkie jego elementy podrzędne
są odwiedzane przed przeniesieniem do innych. Możesz ustawić isTraversalGroup
na
węzły, których nie można zaznaczyć w czytniku ekranu, takie jak kolumny, wiersze czy ramki.
W przykładzie poniżej użyto elementu isTraversalGroup
. Emisja czterech elementów tekstowych.
2 lewe elementy należą do jednego elementu CardBox
, a 2 prawe
należą do innego 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 generuje dane wyjściowe podobne do tych:
Ponieważ nie ustawiono semantyki, czytnik ekranu działa domyślnie możesz przechodzić między elementami z lewej strony na prawą i z góry na dół. Z tego powodu domyślnie, TalkBack odczytuje fragmenty zdań w niewłaściwej kolejności:
„Język tego zdania” → „To zdanie to” → „lewa kolumna”. → „w w prawo”.
Aby poprawnie uporządkować fragmenty, zmień pierwotny fragment kodu na
Od isTraversalGroup
do 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 } ) } }
Parametr isTraversalGroup
jest ustawiany oddzielnie dla każdego tagu CardBox
, dlatego CardBox
podczas sortowania elementów są stosowane granice. W tym przypadku lewa strona
Najpierw odczytywane jest pole CardBox
, a następnie następuje jego CardBox
w prawo.
Teraz TalkBack odczytuje fragmenty zdań we właściwej kolejności:
„Język tego zdania” → „lewa kolumna”. → „To zdanie to” → „w w prawo”.
Dalsze dostosowanie kolejności przemierzania
traversalIndex
to właściwość zmiennoprzecinkowa, która pozwala dostosować TalkBack
kolejność przemierzania. Jeśli zgrupowanie elementów nie jest wystarczające, aby TalkBack
działa prawidłowo, używaj traversalIndex
w połączeniu z
isTraversalGroup
, aby jeszcze lepiej 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ć dodatnia lub ujemna.
- Wartość domyślna to
0f
. - Dotyczy wyłącznie węzłów, dla których można wybrać czytnik ekranu, takich jak elementy na ekranie, takie jak
tekst lub przyciski. Na przykład ustawienie w kolumnie tylko atrybutu
traversalIndex
sprawi, że nie ma żadnego efektu, chyba że kolumna ma również ustawioną wartośćisTraversalGroup
.
Poniższy przykład pokazuje, jak za pomocą parametru traversalIndex
i
isTraversalGroup
razem.
Przykład: Przesuwanie tarczy zegara
Tarcza zegara to typowy scenariusz, w którym standardowa kolejność przemierzania nie w naszej pracy. Przykład w tej sekcji to selektor czasu, przez który użytkownik może przeglądać poprzez liczby na tarczy zegara i wybierz cyfry godziny i minuty przedziały czasu.
W podanym poniżej uproszczonym fragmencie występuje element CircularLayout
, w którym 12
są rysowane liczby, rozpoczynając od 12 i przesuwające 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 nie jest odczytywana logicznie przy domyślnych ustawieniach w kolejności od góry do dołu, TalkBack odczytuje liczby w niewłaściwej kolejności. Aby to naprawić użyj rosnącej wartości licznika, jak pokazano 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 prawidłowo ustawić kolejność przechodzenia między elementami, element CircularLayout
grupy przemierzania i ustaw isTraversalGroup = true
. Potem, w miarę jak każdy tekst na zegarze
narysowanych w układzie, ustaw odpowiadające mu traversalIndex
na licznik
.
Ponieważ wartość licznika stale rośnie, każda wartość zegara
Kolumna traversalIndex
jest większa, ponieważ na ekranie pojawiają się liczby – wartość zegara to 0.
ma traversalIndex
o wartości 0, a wartość zegara 1 ma wartość traversalIndex
równą 1.
Dzięki temu jest ustawiona kolejność ich odczytywania przez TalkBack. Liczby
wewnątrz ciągu CircularLayout
są odczytywane w oczekiwanej kolejności.
Ponieważ wartości traversalIndexes
, które zostały ustawione, odnoszą się tylko do innych
indeksów w tej samej grupie, reszta kolejności ekranów została
i ochrony danych. Inaczej mówiąc, zmiany semantyczne widoczne w poprzednim kodzie
zmienić tylko kolejność w obrębie tarczy zegara, która ma
Ustawiono isTraversalGroup = true
.
Pamiętaj, że jeśli semantyka CircularLayout's
nie zostanie ustawiona na isTraversalGroup =
true
, zmiany typu traversalIndex
będą nadal obowiązywać. Jednak bez stosowania
CircularLayout
, aby je powiązać, odczytywane jest 12 cyfr tarczy zegara
ostatni, po odwiedzeniu wszystkich pozostałych elementów na ekranie. Dzieje się tak
bo wszystkie pozostałe elementy mają domyślną wartość traversalIndex
o wartości 0f
, a
Elementy tekstowe zegara są odczytywane po wszystkich pozostałych elementach 0f
.
Przykład: dostosowanie kolejności przechodzenia między elementami pływającego przycisku polecenia
W tym przykładzie traversalIndex
i isTraversalGroup
określają
kolejność przechodzenia między pływającym przyciskiem polecenia Material Design. Podstawa
w tym przykładzie:
Domyślnie układ w tym przykładzie ma następującą kolejność w TalkBack:
Górny pasek aplikacji → Przykładowe teksty od 0 do 6 → pływający przycisk polecenia (FAB) → Dół Pasek aplikacji
Czytnik ekranu może w pierwszej kolejności skupić się na przycisku PPP. Aby ustawić
traversalIndex
w elemencie Material Design, np. przycisku PPP, 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 atrybutem
W zakresie isTraversalGroup
ustawiono formułę true
i ustawienie traversalIndex
w tym samym polu
(Wartość -1f
jest mniejsza od domyślnej wartości 0f
) oznacza, że pływająca ramka
znajduje się przed wszystkimi innymi elementami ekranowymi.
Następnie możesz umieścić pływające pole i inne elementy w rusztowaniu, implementuje 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 tej 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 wspólne dla wszystkich programistów aplikacji na Androida.
- Tworzenie aplikacji z ułatwieniami dostępu: kluczowe czynności które można usprawnić,
- Zasady ulepszania aplikacji Ułatwienia dostępu: podstawowe zasady pamiętaj o nich podczas pracy nad ułatwianiem dostępu do aplikacji
- Testowanie ułatwień dostępu: Testowanie zasad i narzędzi ułatwień dostępu na Androidzie