Zmiana kolejności przechodzenia

Kolejność przechodzenia to kolejność, w jakiej usługi ułatwień dostępu poruszają się po elementach interfejsu użytkownika. W aplikacji do tworzenia elementy są uporządkowane zgodnie z oczekiwanym porządkiem czytania, który zwykle jest od lewej do prawej, a potem od góry do dołu. W niektórych przypadkach narzędzie Compose może jednak potrzebować dodatkowych wskazówek, aby określić prawidłową kolejność czytania.

isTraversalGrouptraversalIndex to właściwości semantyczne, które umożliwiają wpływanie na kolejność przetwarzania usług ułatwień dostępu w sytuacjach, w których domyślny algorytm sortowania Compose jest niewystarczający. isTraversalGroupidentyfikuje grupy o dużej wartości semantycznej, które wymagają dostosowania, a traversalIndexdostosowuje kolejność poszczególnych elementów w tych grupach. Możesz użyć tylko isTraversalGroup, aby wskazać, że wszystkie elementy w grupie powinny być wybierane razem, lub isTraversalGroup, aby dostosować ustawienia.traversalIndex

Aby kontrolować kolejność przechodzenia przez elementy w czytniku ekranu, użyj w aplikacji elementów isTraversalGrouptraversalIndex.

Grupowanie elementów na potrzeby przechodzenia

isTraversalGroup to właściwość logiczna, która określa, czy węzeł semantics jest grupą przeszukiwania. Ten typ węzła służy jako granica lub linia oddzielająca elementy podrzędne.

Ustawienie isTraversalGroup = true w węźle oznacza, że wszystkie elementy podrzędne tego węzła są odwiedzane przed przejściem do innych elementów. Możesz ustawić isTraversalGroup w węzłach, które nie są dostępne dla czytnika ekranu, takich jak kolumny, wiersze czy pola.

W tym przykładzie użyto funkcji isTraversalGroup. Wypisuje 4 elementy tekstowe. Dwa elementy po lewej stronie należą do jednego elementu CardBox, a dwa po prawej stronie – 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 wyświetla dane wyjściowe podobne do tych:

Układ z 2 kolumnami tekstu. W lewej kolumnie widać napis „To zdanie jest w lewej kolumnie”, a w prawej kolumnie „To zdanie jest po prawej stronie”.
Rysunek 1. Układ z 2 zdaniami (jedno w lewej kolumnie, drugie w prawej kolumnie).

Ponieważ nie ustawiono żadnej semantyki, domyślne działanie czytnika ekranu polega na przechodzeniu przez elementy od lewej do prawej i od góry do dołu. Z tego powodu TalkBack odczytuje fragmenty zdania w niewłaściwej kolejności:

„To zdanie jest w sekcji” → „To zdanie jest” → „w lewej kolumnie”. → „po prawej stronie”.

Aby ustawić prawidłowe kolejności fragmentów, zmodyfikuj oryginalny fragment kodu, aby ustawić wartość 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ż isTraversalGroup jest ustawiany osobno dla każdego CardBox, podczas sortowania elementów brane są pod uwagę granice CardBox. W tym przypadku najpierw odczytana zostanie lewa CardBox, a potem prawa CardBox.

Teraz TalkBack odczytuje fragmenty zdania w prawidłowej kolejności:

„To zdanie znajduje się” → „w lewej kolumnie”. → „To zdanie jest” → „po prawej stronie”.

Dostosowywanie kolejności przeszukiwania

traversalIndex to właściwość typu float, która umożliwia dostosowywanie kolejności przechodzenia TalkBack. Jeśli grupowanie elementów nie wystarcza do prawidłowego działania TalkBack, użyj traversalIndex w połączeniu z isTraversalGroup, aby dodatkowo dostosować kolejność elementów wyświetlanych przez czytnik ekranu.

Właściwość traversalIndex ma te cechy:

  • Elementy o mniejszych wartościach atrybutu traversalIndex mają wyższy priorytet.
  • Mogą być pozytywne lub negatywne.
  • Wartość domyślna to 0f.
  • Aby indeks przeszukiwania mógł wpływać na sposób przeszukiwania, musi być ustawiony na komponencie, który będzie można wybrać i na którym będzie można ustawić fokus za pomocą usług ułatwień dostępu, takich jak elementy na ekranie, np. tekst lub przyciski.
    • Ustawienie tylko traversalIndex, na przykład Column, nie będzie miało żadnego wpływu, chyba że kolumna ma też ustawioną wartość isTraversalGroup.

Ten przykład pokazuje, jak używać razem funkcji traversalIndexisTraversalGroup.

Tarcza zegara to typowy scenariusz, w którym standardowe sortowanie nie działa. Przykład w tej sekcji to selektor czasu, w którym użytkownik może przewijać cyfry na tarczy zegara i wybierać cyfry dla godzin i minut.

Tarcza zegara z wyświetlonym selektorem czasu.
Rysunek 2. Obraz tarczy zegara.

W tym uproszczonym fragmencie kodu znajduje się element CircularLayout, w którym narysowano 12 liczb, zaczynając od 12 i poruszając się zgodnie z kierunkiem ruchu wskazówek zegara:

@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())
    }
}

Tarcza zegara nie jest odczytywana w logiczny sposób, czyli od lewej do prawej i od góry do dołu. Dlatego TalkBack odczytuje liczby w nieporządku. Aby to naprawić, użyj wartości licznika zwiększającego się, jak pokazano w tym fragmencie kodu:

@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ść przeszukiwania, najpierw ustaw CircularLayout jako grupę przeszukiwania i ustaw isTraversalGroup = true. Następnie, gdy tekst zegara zostanie narysowany na stronie, ustaw odpowiednią wartość traversalIndex na wartość licznika.

Ponieważ wartość licznika stale rośnie, każda wartość zegara traversalIndex jest większa, gdy dodawane są kolejne liczby na ekranie. Wartość zegara 0 ma traversalIndex równy 0, a wartość zegara 1 ma traversalIndex równy 1. W ten sposób określasz kolejność, w jakiej TalkBack ma czytać te elementy. Liczby w grupie CircularLayout są odczytywane w oczekiwanej kolejności.

Ustawione wartości traversalIndexes są względne tylko do innych indeksów w ramach tego samego pogrupowania, więc pozostała kolejność na ekranie została zachowana. Inaczej mówiąc, zmiany semantyczne pokazane w poprzednim fragmencie kodu zmieniają tylko kolejność na tarczy zegara, która ma ustawioną wartość isTraversalGroup = true.

Pamiętaj, że nawet bez ustawienia semantyki CircularLayout's na isTraversalGroup = true zmiany traversalIndex nadal będą miały zastosowanie. Jednak bez znaku CircularLayout, który je łączy, 12 cyfr tarczy zegara jest odczytywanych na końcu, gdy wszystkie inne elementy na ekranie zostaną odwiedzone. Dzieje się tak, ponieważ wszystkie inne elementy mają domyślną wartość traversalIndex 0f, a elementy tekstu zegara są odczytywane po wszystkich pozostałych elementach 0f.

Informacje dotyczące interfejsów API

Podczas korzystania z interfejsów API do przeszukiwania według ścieżki należy wziąć pod uwagę te kwestie:

  • W elemencie nadrzędnym zawierającym elementy pogrupowane należy ustawić parametr isTraversalGroup = true.
  • W komponencie podrzędnym zawierającym semantyczne dane należy ustawić wartość traversalIndex, która będzie wybierana przez usługi ułatwień dostępu.
  • Upewnij się, że wszystkie analizowane elementy znajdują się na tym samym poziomie zIndex, ponieważ wpływa to również na semantykę i kolejność przechodzenia.
  • Upewnij się, że nie ma niepotrzebnie scalonych semantyk, ponieważ może to wpływać na to, do których komponentów są stosowane indeksy przeszukiwania.