Wichtige Schritte zur Verbesserung der Barrierefreiheit der Funktion „Compose“

Um Menschen mit Bedürfnissen an der Barrierefreiheit zu helfen, Ihre App erfolgreich zu verwenden, App, um wichtige Anforderungen an die Barrierefreiheit zu erfüllen.

Mindestgröße für Berührungszielbereiche berücksichtigen

Jedes Bildschirmelement, das angeklickt, angetippt oder mit dem es interagieren kann, sollte für eine zuverlässige Interaktion groß genug. Wenn Sie die Größe dieser Elemente Stellen Sie die Mindestgröße auf 48 dp ein, um dem Material Design Richtlinien zur Barrierefreiheit.

Materialkomponenten wie Checkbox, RadioButton, Switch, Slider und Surface – legen diese Mindestgröße intern fest, aber nur wenn die Komponente Nutzeraktionen empfangen kann. Wenn beispielsweise ein Checkbox onCheckedChange-Parameter auf einen Wert ungleich null gesetzt ist, enthält das Kästchen muss mindestens 48 dp breit und hoch sein.

@Composable
private fun CheckableCheckbox() {
    Checkbox(checked = true, onCheckedChange = {})
}

Ist der Parameter onCheckedChange auf null gesetzt, wird der Abstand nicht enthalten, da mit der Komponente nicht direkt interagiert werden kann.

@Composable
private fun NonClickableCheckbox() {
    Checkbox(checked = true, onCheckedChange = null)
}

<ph type="x-smartling-placeholder">
</ph>
Abbildung 1. Ein Kästchen ohne Abstand.

Bei der Implementierung von Auswahlsteuerungen wie Switch, RadioButton oder Checkbox festlegen, wird das Verhalten anklickbar in der Regel auf einen übergeordneten Container verschoben, wobei Folgendes festgelegt ist: den Klick-Callback in der zusammensetzbaren Funktion zu null hinzu und fügen Sie ein toggleable- oder selectable-Modifikator in die übergeordnete zusammensetzbare Funktion.

@Composable
private fun CheckableRow() {
    MaterialTheme {
        var checked by remember { mutableStateOf(false) }
        Row(
            Modifier
                .toggleable(
                    value = checked,
                    role = Role.Checkbox,
                    onValueChange = { checked = !checked }
                )
                .padding(16.dp)
                .fillMaxWidth()
        ) {
            Text("Option", Modifier.weight(1f))
            Checkbox(checked = checked, onCheckedChange = null)
        }
    }
}

Wenn die Größe einer anklickbaren zusammensetzbaren Funktion kleiner ist als das minimale Berührungszielbereich wird der Berührungszielbereich trotzdem vergrößert. Dazu wird das Feld die Größe des Berührungszielbereichs außerhalb der Grenzen der zusammensetzbaren Funktion liegt.

Das folgende Beispiel enthält ein sehr kleines anklickbares Box. Berührungszielbereich wird automatisch über die Grenzen von Box hinaus erweitert. Tippen Sie daher neben dem Box löst trotzdem das Klickereignis aus.

@Composable
private fun SmallBox() {
    var clicked by remember { mutableStateOf(false) }
    Box(
        Modifier
            .size(100.dp)
            .background(if (clicked) Color.DarkGray else Color.LightGray)
    ) {
        Box(
            Modifier
                .align(Alignment.Center)
                .clickable { clicked = !clicked }
                .background(Color.Black)
                .size(1.dp)
        )
    }
}

Um mögliche Überschneidungen zwischen den Berührungsbereichen verschiedener zusammensetzbarer Funktionen zu vermeiden, Verwenden Sie eine Mindestgröße, die für die zusammensetzbare Funktion groß genug ist. In diesem Beispiel bedeutet, dass der sizeIn-Modifikator verwendet wird, um die Mindestgröße für das innere Feld festzulegen:

@Composable
private fun LargeBox() {
    var clicked by remember { mutableStateOf(false) }
    Box(
        Modifier
            .size(100.dp)
            .background(if (clicked) Color.DarkGray else Color.LightGray)
    ) {
        Box(
            Modifier
                .align(Alignment.Center)
                .clickable { clicked = !clicked }
                .background(Color.Black)
                .sizeIn(minWidth = 48.dp, minHeight = 48.dp)
        )
    }
}

Klicklabels hinzufügen

Sie können ein Klicklabel verwenden, um dem Klickverhalten zusammensetzbar. Klicklabels beschreiben, was passiert, wenn Nutzende mit dem zusammensetzbar. Bedienungshilfen nutzen Klicklabels, um die App für Nutzenden mit spezifischen Bedürfnissen.

Legen Sie das Klicklabel fest, indem Sie einen Parameter im clickable-Modifikator übergeben:

@Composable
private fun ArticleListItem(openArticle: () -> Unit) {
    Row(
        Modifier.clickable(
            // R.string.action_read_article = "read article"
            onClickLabel = stringResource(R.string.action_read_article),
            onClick = openArticle
        )
    ) {
        // ..
    }
}

Wenn Sie keinen Zugriff auf den klickbaren Modifikator haben, geben Sie Klicklabel im Semantik-Modifikator:

@Composable
private fun LowLevelClickLabel(openArticle: () -> Boolean) {
    // R.string.action_read_article = "read article"
    val readArticleLabel = stringResource(R.string.action_read_article)
    Canvas(
        Modifier.semantics {
            onClick(label = readArticleLabel, action = openArticle)
        }
    ) {
        // ..
    }
}

Visuelle Elemente beschreiben

Wenn Sie eine zusammensetzbare Funktion Image oder Icon definieren, automatische Methode, damit das Android-Framework versteht, worum es in der App geht. angezeigt wird. Sie müssen eine Beschreibung des visuellen Elements in Textform übergeben.

Stellen Sie sich einen Bildschirm vor, in dem der Nutzer die aktuelle Seite mit Freunden teilen kann. Dieses ein anklickbares Symbol zum Teilen enthält:

Ein Streifen aus anklickbaren Symbolen mit dem

Aufgrund des Symbols allein kann das Android-Framework es nicht visuell eingeschränkter Nutzer. Das Android-Framework benötigt eine zusätzliche Beschreibung in Textform auf das Symbol.

Der Parameter contentDescription beschreibt ein visuelles Element. Verwenden Sie eine lokalisierte -String, da er für den Nutzer sichtbar ist.

@Composable
private fun ShareButton(onClick: () -> Unit) {
    IconButton(onClick = onClick) {
        Icon(
            imageVector = Icons.Filled.Share,
            contentDescription = stringResource(R.string.label_share)
        )
    }
}

Einige visuelle Elemente sind rein dekorativ und Sie möchten vielleicht an die Nutzenden zu übermitteln. Wenn Sie den Parameter contentDescription auf null setzen, gilt Folgendes: um dem Android-Framework anzuzeigen, dass dieses Element nicht Aktionen oder Zustand.

@Composable
private fun PostImage(post: Post, modifier: Modifier = Modifier) {
    val image = post.imageThumb ?: painterResource(R.drawable.placeholder_1_1)

    Image(
        painter = image,
        // Specify that this image has no semantic meaning
        contentDescription = null,
        modifier = modifier
            .size(40.dp, 40.dp)
            .clip(MaterialTheme.shapes.small)
    )
}

Es liegt an Ihnen zu entscheiden, ob ein bestimmtes visuelles Element contentDescription Fragen Sie sich, ob das Element Informationen vermittelt, die die Nutzende für ihre Aufgabe brauchen. Wenn nicht, ist es besser, die aus der Beschreibung heraus.

Elemente zusammenführen

Mit Bedienungshilfen wie TalkBack und Schalterzugriff können Nutzer den Fokus verschieben für verschiedene Elemente auf dem Bildschirm. Es ist wichtig, dass sich die Elemente Detaillierungsgrad zu verbessern. Wenn alle zusammensetzbaren Funktionen auf unterer Ebene und fokussiert sind, müssen die Nutzenden viel interagieren, um sich über den Bildschirm zu bewegen. Wenn Elemente zu aggressiv zusammengeführt werden, wissen Nutzende möglicherweise nicht, welche Elemente zusammengehören

Wenn Sie einen clickable-Modifikator auf eine zusammensetzbare Funktion anwenden, führt automatisch alle Elemente zusammen, die die zusammensetzbare Funktion enthält. Dies gilt auch für ListItem; werden die Elemente eines Listeneintrags zusammengeführt sehen sie sich als ein Element an.

Es ist möglich, eine Reihe von zusammensetzbaren Funktionen zu haben, die eine logische Gruppe bilden. Gruppe ist nicht anklickbar oder Teil eines Listenelements. Barrierefreiheit um sie als ein Element zu betrachten. Stellen Sie sich z. B. eine zusammensetzbare Funktion vor, Der Avatar eines Nutzers, sein Name und einige zusätzliche Informationen werden angezeigt:

Eine Gruppe von UI-Elementen, die den Namen eines Nutzers enthalten. Der Name ist ausgewählt.

Du kannst „Schreiben“ aktivieren, um diese Elemente zusammenzuführen, indem du das mergeDescendants verwendest im semantics-Modifikator. So können Bedienungshilfen Nur das zusammengeführte Element und alle Semantikeigenschaften der Nachfolger auswählen zusammengeführt werden.

@Composable
private fun PostMetadata(metadata: Metadata) {
    // Merge elements below for accessibility purposes
    Row(modifier = Modifier.semantics(mergeDescendants = true) {}) {
        Image(
            imageVector = Icons.Filled.AccountCircle,
            contentDescription = null // decorative
        )
        Column {
            Text(metadata.author.name)
            Text("${metadata.date} • ${metadata.readTimeMinutes} min read")
        }
    }
}

Bedienungshilfen konzentrieren sich jetzt auf den gesamten Container auf einmal und führen sie zusammen. ihre Inhalte:

Eine Gruppe von UI-Elementen, die den Namen eines Nutzers enthalten. Alle Elemente werden gemeinsam ausgewählt.

Benutzerdefinierte Aktionen hinzufügen

Sehen Sie sich den folgenden Listeneintrag an:

Ein typischer Listeneintrag, der einen Artikeltitel, einen Autor und ein Lesezeichensymbol enthält.

Wenn Sie einen Screenreader wie TalkBack verwenden, um sich vorlesen zu lassen, was auf der wird zuerst das gesamte Element und dann das Lesezeichensymbol ausgewählt.

Das Listenelement mit allen ausgewählten Elementen

Den Listeneintrag, in dem nur das Lesezeichensymbol ausgewählt ist

In einer langen Liste kann sich dies sehr wiederholen. Ein besserer Ansatz besteht darin, eine benutzerdefinierte Aktion definieren, mit der ein Nutzer den Artikel als Lesezeichen speichern kann. Wichtige Hinweise dass Sie das Verhalten des Lesezeichensymbols sich selbst ein, um sicherzustellen, dass sie nicht von der Bedienungshilfe ausgewählt wird. Dieses erfolgt mit dem clearAndSetSemantics-Modifikator:

@Composable
private fun PostCardSimple(
    /* ... */
    isFavorite: Boolean,
    onToggleFavorite: () -> Boolean
) {
    val actionLabel = stringResource(
        if (isFavorite) R.string.unfavorite else R.string.favorite
    )
    Row(
        modifier = Modifier
            .clickable(onClick = { /* ... */ })
            .semantics {
                // Set any explicit semantic properties
                customActions = listOf(
                    CustomAccessibilityAction(actionLabel, onToggleFavorite)
                )
            }
    ) {
        /* ... */
        BookmarkButton(
            isBookmarked = isFavorite,
            onClick = onToggleFavorite,
            // Clear any semantics properties set on this node
            modifier = Modifier.clearAndSetSemantics { }
        )
    }
}

Zustand eines Elements beschreiben

Eine zusammensetzbare Funktion kann ein stateDescription für Semantik definieren, die die Das Android-Framework wird verwendet, um den Status der zusammensetzbaren Funktion auszulesen. Für eine ein-/ausschaltbare zusammensetzbare Funktion oder „nicht aktiviert“ Bundesstaat. In einigen Fällen möchten Sie die Beschreibung des Standardstatus überschreiben, die in Compose verwendet werden. Geben Sie dazu den Bundesstaat bevor Sie eine zusammensetzbare Funktion als ein-/ausschaltbar definieren:

@Composable
private fun TopicItem(itemTitle: String, selected: Boolean, onToggle: () -> Unit) {
    val stateSubscribed = stringResource(R.string.subscribed)
    val stateNotSubscribed = stringResource(R.string.not_subscribed)
    Row(
        modifier = Modifier
            .semantics {
                // Set any explicit semantic properties
                stateDescription = if (selected) stateSubscribed else stateNotSubscribed
            }
            .toggleable(
                value = selected,
                onValueChange = { onToggle() }
            )
    ) {
        /* ... */
    }
}

Überschriften definieren

Apps zeigen manchmal viele Inhalte auf einem Bildschirm in einem scrollbaren Container an. Beispielsweise kann ein Bildschirm den gesamten Inhalt eines Artikels zeigen, den die Nutzenden liest gerade:

Screenshot eines Blogposts mit dem Artikeltext in einem scrollbaren Container.

Nutzende mit Anforderungen an die Barrierefreiheit haben Schwierigkeiten, auf einem solchen Bildschirm zu navigieren. Zur Unterstützung Navigationselemente angeben, welche Elemente Überschriften sind. Im vorherigen Beispiel wurde jeder Unterabschnittstitel könnte als Überschrift für Barrierefreiheit definiert werden. Einige Mit Bedienungshilfen wie TalkBack können Nutzer von heading zu heading.

In „Compose“ geben Sie an, dass eine zusammensetzbare Funktion eine Überschrift ist, indem Sie ihre semantics-Property:

@Composable
private fun Subsection(text: String) {
    Text(
        text = text,
        style = MaterialTheme.typography.headlineSmall,
        modifier = Modifier.semantics { heading() }
    )
}

Benutzerdefinierte zusammensetzbare Funktionen verarbeiten

Wenn du bestimmte Material-Komponenten in deiner App durch benutzerdefinierte müssen Sie auch die Barrierefreiheit berücksichtigen.

Angenommen, Sie ersetzen das Material Checkbox durch Ihre eigene Implementierung. Sie könnten vergessen, den triStateToggleable-Modifikator hinzuzufügen, mit dem die Bedienungshilfen für diese Komponente.

Als Faustregel gilt: Sehen Sie sich die Implementierung der Komponente in der Material-Bibliothek zu öffnen und jedes gefundene Bedienungshilfeverhalten nachzuahmen. Nutzen Sie außerdem intensiv die Grundlagen-Modifikatoren im Gegensatz zur UI-Ebene. , da diese bereits Überlegungen zur Barrierefreiheit umfassen.

Testen Sie die Implementierung Ihrer benutzerdefinierten Komponente mit mehreren Bedienungshilfen überprüfen, um ihr Verhalten zu überprüfen.

Weitere Informationen