Durchlaufreihenfolge festlegen

Standardmäßig ist das Verhalten des Screenreaders als Bedienungshilfe in einer App zum Schreiben von Texten implementiert in der erwarteten Lesereihenfolge, also von links nach rechts und dann von oben nach unten. Es gibt jedoch einige Arten von App-Layouts, bei denen der Algorithmus Lesereihenfolge ändern, ohne zusätzliche Hinweise. In aufrufbasierten Apps haben Sie folgende Möglichkeiten: Beheben Sie solche Probleme mit den Properties traversalBefore und traversalAfter. Seit Composer 1.5 bietet Compose eine genauso flexible API mit konzeptionelles Modell an.

isTraversalGroup und traversalIndex sind semantische Attribute, die können Sie die Bedienungshilfen und die Fokusreihenfolge von TalkBack in Szenarien steuern, in denen die Standardsortieralgorithmus nicht geeignet ist. isTraversalGroup identifiziert semantisch wichtige Gruppen, während traversalIndex die Reihenfolge der einzelne Elemente innerhalb dieser Gruppen. Sie können nur isTraversalGroup verwenden, oder mit traversalIndex für weitere Anpassungen.

Verwenden Sie isTraversalGroup und traversalIndex in Ihrem App zur Steuerung der Durchquerungsreihenfolge für Screenreader.

Elemente mit isTraversalGroup gruppieren

isTraversalGroup ist ein boolesches Attribut, das definiert, ob eine Semantik Knoten ist eine Durchlaufgruppe. Diese Art von Knoten ist ein Knoten, dessen Funktion darin besteht, als Begrenzung oder Grenze bei der Organisation der untergeordneten Knoten des Knotens.

Wenn Sie isTraversalGroup = true für einen Knoten festlegen, werden alle untergeordneten Elemente dieses Knotens bevor Sie zu anderen Elementen wechseln. Du kannst isTraversalGroup festlegen auf Fokussierbare Knoten ohne Screenreader, z. B. Spalten, Zeilen oder Felder.

Im folgenden Beispiel wird isTraversalGroup verwendet. Es werden vier Textelemente ausgegeben. Die Die beiden linken Elemente gehören zu einem CardBox-Element, während die beiden rechten zu einem anderen CardBox-Element gehören:

// 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
        )
    }
}

Die Ausgabe des Codes sieht in etwa so aus:

<ph type="x-smartling-placeholder">
</ph> Layout mit zwei Textspalten, wobei in der linken Spalte
  Satz steht in der linken Spalte&#39; und in der rechten Spalte
&quot;This sentence is on the right&quot; (Dieser Satz befindet sich auf der rechten Seite).
Abbildung 1: Ein Layout mit zwei Sätzen (einer auf der linken Seite) und eines in der rechten Spalte).

Da keine Semantik festgelegt wurde, ist das Standardverhalten des Screenreaders um Elemente von links nach rechts und von oben nach unten zu durchqueren. Aus diesem Grund Standardmäßig werden die Satzfragmente von TalkBack in der falschen Reihenfolge vorgelesen:

„Dieser Satz ist auf“ → „Dieser Satz ist“ → „die linke Spalte“. → "auf der richtig.“

Um die Fragmente richtig zu ordnen, ändern Sie das ursprüngliche Snippet, isTraversalGroup in 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 }
        )
    }
}

Da isTraversalGroup speziell für jede CardBox festgelegt wird, ist die CardBox -Grenzen gelten beim Sortieren ihrer Elemente. In diesem Fall ist die linke Zuerst wird CardBox gelesen, gefolgt vom rechten CardBox.

Jetzt liest TalkBack die Satzfragmente in der richtigen Reihenfolge vor:

„Dieser Satz ist auf“ → „die linke Spalte“. → „Dieser Satz ist“ → "auf der richtig.“

Durchlaufreihenfolge weiter anpassen

traversalIndex ist eine Float-Eigenschaft, mit der Sie TalkBack anpassen können Durchlaufreihenfolge festlegen. Wenn das Gruppieren von Elementen für TalkBack nicht ausreicht, ordnungsgemäß funktionieren, verwenden Sie traversalIndex in Verbindung mit isTraversalGroup, um die Reihenfolge der Screenreader weiter anzupassen.

Das Attribut traversalIndex hat die folgenden Eigenschaften:

  • Elemente mit niedrigeren traversalIndex-Werten haben Vorrang.
  • Kann positiv oder negativ sein.
  • Der Standardwert ist 0f.
  • Betrifft nur Screenreader-fokussierbare Knoten, z. B. Bildschirmelemente wie Text oder Schaltflächen. Wenn Sie beispielsweise nur traversalIndex für eine Spalte festlegen, haben keine Auswirkungen, es sei denn, für die Spalte wurde auch isTraversalGroup festgelegt.

Das folgende Beispiel zeigt, wie Sie traversalIndex und isTraversalGroup zusammen.

Beispiel: Ziffernblatt durchlaufen

Bei einem Ziffernblatt handelt es sich um ein häufiges Szenario, in dem arbeiten. Das Beispiel in diesem Abschnitt ist eine Zeitauswahl, Ziffernblatt durchsehen und Ziffern für die Stunde und die Minute auswählen Slots.

<ph type="x-smartling-placeholder">
</ph> Ein Ziffernblatt mit einer Zeitauswahl darüber.
Abbildung 2: Ein Bild eines Zifferblatts.

Im folgenden vereinfachten Snippet gibt es ein CircularLayout, in dem 12 Es werden Zahlen gezeichnet, die bei 12 beginnen und sich im Uhrzeigersinn um den Kreis bewegen:

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

Da die Uhranzeige mit der Standardeinstellung von links nach rechts und Reihenfolge von oben nach unten verwendet, liest TalkBack die Zahlen in der falschen Reihenfolge vor. Um das Problem zu beheben verwenden Sie den inkrementellen Zählerwert, wie im folgenden Snippet gezeigt:

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

Um die Durchlaufreihenfolge richtig festzulegen, legen Sie zuerst den CircularLayout als Durchlaufgruppe und legen Sie isTraversalGroup = true fest. Da jeder Ziffernblatt-Text auf das Layout gezeichnet haben, legen Sie die entsprechende traversalIndex auf den Zähler fest. Wert.

Da der Zählerwert kontinuierlich ansteigt, traversalIndex ist größer, da Zahlen zum Bildschirm hinzugefügt werden – der Uhrwert 0 hat einen traversalIndex von 0 und der Uhrwert 1 hat den traversalIndex von 1. Auf diese Weise wird die Reihenfolge festgelegt, in der TalkBack vorliest. Die Zahlen innerhalb der CircularLayout in der erwarteten Reihenfolge gelesen werden.

Da die festgelegten traversalIndexes nur relativ zu anderen innerhalb derselben Gruppierung besteht, ist der Rest der Bildschirmreihenfolge beibehalten werden. Mit anderen Worten, die im vorstehenden Code dargestellten semantischen Änderungen das Snippet nur die Reihenfolge innerhalb der Uhranzeige ändert, isTraversalGroup = true festgelegt.

Hinweis: Wenn Sie die Semantik von CircularLayout's nicht auf isTraversalGroup = true festlegen, werden die traversalIndex-Änderungen weiterhin angewendet. Ohne die CircularLayout, um sie zu binden, werden die zwölf Ziffern des Ziffernblatts vorgelesen nachdem alle anderen Elemente auf dem Bildschirm besucht wurden. Dies geschieht da für alle anderen Elemente der Standardwert für traversalIndex 0f ist und der Wert Ziffernblatt-Textelemente werden nach allen anderen 0f-Elementen vorgelesen.

Beispiel: Durchlaufreihenfolge für unverankerte Aktionsschaltfläche anpassen

In diesem Beispiel steuern traversalIndex und isTraversalGroup den Durchlaufreihenfolge einer unverankerten Aktionsschaltfläche (UAS) von Material Design. Grundlage dieses Beispiels ist das folgende Layout:

<ph type="x-smartling-placeholder">
</ph> Ein Layout mit einer oberen App-Leiste, Beispieltext, einer unverankerten Aktionsschaltfläche und
  App-Leiste am unteren Rand.
Abbildung 3: Layout mit einer oberen App-Leiste, Beispieltext, einer unverankerten Aktionsschaltfläche und einer App-Leiste unten.

Standardmäßig hat das Layout in diesem Beispiel die folgende TalkBack-Reihenfolge:

Obere App-Leiste → Beispieltexte 0 bis 6 → unverankerte Aktionsschaltfläche (UAS) → Unten App-Leiste

Möglicherweise soll sich der Screenreader zuerst auf die UAS konzentrieren. Um eine traversalIndex für ein Material-Element wie eine FAB:

@Composable
fun FloatingBox() {
    Box(modifier = Modifier.semantics { isTraversalGroup = true; traversalIndex = -1f }) {
        FloatingActionButton(onClick = {}) {
            Icon(imageVector = Icons.Default.Add, contentDescription = "fab icon")
        }
    }
}

In diesem Snippet wird ein Feld mit isTraversalGroup wurde auf true gesetzt und ein traversalIndex für dieselbe Box festgelegt (-1f ist niedriger als der Standardwert 0f) bedeutet, dass das schwebende Feld vor allen anderen Bildschirmelementen.

Als Nächstes können Sie die unverankerte Box und andere Elemente in ein Gerüst einfügen, ein Material-Design-Layout implementiert:

@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 interagiert mit den Elementen in der folgenden Reihenfolge:

UAS → Obere App-Leiste → Beispieltexte 0 bis 6 → Untere App-Leiste

Weitere Informationen