Damit Menschen mit Anforderungen an die Barrierefreiheit Ihre App erfolgreich verwenden können, sollten Sie sie so gestalten, dass sie wichtige Anforderungen an die Barrierefreiheit erfüllt.
Mindestgrößen für Berührungszielbereiche berücksichtigen
Jedes Bildschirmelement, das angeklickt, angetippt oder verwendet werden kann, sollte groß genug sein, um eine zuverlässige Interaktion zu ermöglichen. Achten Sie bei der Größenanpassung dieser Elemente darauf, die Mindestgröße auf 48 dp festzulegen, um den Richtlinien für Bedienungshilfen in Material Design zu entsprechen.
Materialkomponenten wie Checkbox
, RadioButton
, Switch
, Slider
und Surface
legen diese Mindestgröße intern fest, aber nur, wenn die Komponente Nutzeraktionen empfangen kann. Wenn beispielsweise der Parameter onCheckedChange
einer Checkbox
auf einen Wert ungleich Null gesetzt ist, schließt das Kästchen einen Innenrand ein, sodass eine Breite und Höhe von mindestens 48 dp erreicht wird.
@Composable private fun CheckableCheckbox() { Checkbox(checked = true, onCheckedChange = {}) }
Wenn der Parameter onCheckedChange
auf null gesetzt ist, wird der Abstand nicht verwendet, da die Komponente nicht direkt interagiert werden kann.
@Composable private fun NonClickableCheckbox() { Checkbox(checked = true, onCheckedChange = null) }
Wenn Sie Auswahlsteuerelemente wie Switch
, RadioButton
oder Checkbox
implementieren, heben Sie normalerweise das anklickbare Verhalten auf einen übergeordneten Container an, setzen den Klick-Callback der zusammensetzbaren Funktion auf null
und fügen der übergeordneten zusammensetzbaren Funktion den Modifikator toggleable
oder selectable
hinzu.
@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 die Mindestgröße für den Berührungszielbereich, wird die Größe des Berührungszielbereichs trotzdem in der Funktion "Compose" erhöht. Dazu wird die Größe des Berührungszielbereichs außerhalb der Grenzen der zusammensetzbaren Funktion erweitert.
Das folgende Beispiel enthält ein sehr kleines anklickbares Box
-Objekt. Der Berührungszielbereich wird automatisch über die Grenzen von Box
hinaus erweitert. Das Tippen neben Box
löst also weiterhin 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) ) } }
Verwenden Sie für die zusammensetzbare Funktion immer eine ausreichend große Mindestgröße, um eine mögliche Überschneidung zwischen den Berührungsbereichen verschiedener zusammensetzbarer Funktionen zu vermeiden. Im Beispiel würde dies bedeuten, 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
Mit einem Klicklabel können Sie dem Klickverhalten einer zusammensetzbaren Funktion eine semantische Bedeutung verleihen. Klicklabels beschreiben, was passiert, wenn der Nutzer mit der zusammensetzbaren Funktion interagiert. Bedienungshilfen verwenden Klicklabels, um die App für Nutzer mit bestimmten Anforderungen zu beschreiben.
Übergeben Sie im clickable
-Modifikator einen Parameter, um das Klicklabel festzulegen:
@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 anklickbaren Modifikator haben, legen Sie alternativ das Klicklabel im Modifikator semantics fest:
@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 aus Image
oder Icon
definieren, kann das Android-Framework nicht automatisch verstehen, was die App gerade anzeigt. Sie müssen eine Textbeschreibung des visuellen Elements übergeben.
Stellen Sie sich einen Bildschirm vor, auf dem Nutzende die aktuelle Seite mit Freunden teilen können. Dieser Bildschirm enthält ein anklickbares Freigabesymbol:
Anhand des Symbols allein kann das Android-Framework es einem sehbehinderten Nutzer nicht beschreiben. Das Android-Framework benötigt eine zusätzliche Textbeschreibung des Symbols.
Der Parameter contentDescription
beschreibt ein visuelles Element. Verwende einen lokalisierten String, so wie 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 möchten den Nutzern nicht unbedingt vermittelt werden. Wenn Sie den contentDescription
-Parameter auf null
setzen, geben Sie im Android-Framework an, dass diesem Element keine Aktionen oder Status zugeordnet sind.
@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) ) }
Du musst entscheiden, ob ein bestimmtes visuelles Element ein contentDescription
benötigt. Fragen Sie sich, ob das Element Informationen vermittelt,
die Nutzende zur Ausführung ihrer Aufgabe benötigen. Andernfalls ist es besser, die Beschreibung wegzulassen.
Elemente zusammenführen
Mit Bedienungshilfen wie TalkBack und Schalterzugriff können Nutzer den Fokus auf Elemente auf dem Bildschirm verschieben. Es ist wichtig, dass die Elemente mit dem richtigen Detaillierungsgrad fokussiert sind. Wenn jede einzelne zusammensetzbare Funktion auf unterer Ebene des Bildschirms unabhängig voneinander fokussiert ist, müssen Nutzer viel interagieren, um sich über den Bildschirm zu bewegen. Wenn Elemente zu aggressiv aufeinander abgestimmt werden, verstehen Nutzer möglicherweise nicht, welche Elemente zusammengehören.
Wenn Sie einen clickable
-Modifikator auf eine zusammensetzbare Funktion anwenden, werden in der Funktion „Compose“ automatisch alle Elemente zusammengeführt, die in der zusammensetzbaren Funktion enthalten sind. Dies gilt auch für ListItem
. Die Elemente in einem Listenelement werden zusammengeführt und von Bedienungshilfen als ein Element angesehen.
Es ist möglich, eine Reihe von zusammensetzbaren Funktionen zu haben, die eine logische Gruppe bilden. Diese Gruppe ist jedoch nicht anklickbar oder Teil eines Listenelements. Die Bedienungshilfen sollten sie trotzdem als ein Element sehen können. Stellen Sie sich z. B. eine zusammensetzbare Funktion vor, die den Avatar eines Nutzers, seinen Namen und einige zusätzliche Informationen anzeigt:
Sie können festlegen, dass diese Elemente in „Compose“ zusammengeführt werden. Verwenden Sie dazu den Parameter mergeDescendants
im Modifikator semantics
. Auf diese Weise wählen Bedienungshilfen nur das zusammengeführte Element aus und alle semantischen Attribute der untergeordneten Elemente werden zusammengeführt.
@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 und führen deren Inhalte zusammen:
Benutzerdefinierte Aktionen hinzufügen
Sehen Sie sich den folgenden Listeneintrag an:
Wenn Sie einen Screenreader wie TalkBack verwenden, um zu hören, was auf dem Bildschirm angezeigt wird, wird zuerst das gesamte Element und dann das Lesezeichensymbol ausgewählt.
Bei einer langen Liste kann sich das oft wiederholen. Ein besserer Ansatz besteht darin, eine benutzerdefinierte Aktion zu definieren, mit der Nutzer das Element als Lesezeichen speichern können. Außerdem müssen Sie das Verhalten des Lesezeichensymbols selbst explizit entfernen, damit es nicht von der Bedienungshilfe ausgewählt wird. Dazu verwenden Sie den Modifikator clearAndSetSemantics
:
@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 { } ) } }
Status eines Elements beschreiben
Eine zusammensetzbare Funktion kann eine stateDescription
für die Semantik definieren, mit der das Android-Framework den Status ausliest, in dem sich die zusammensetzbare Funktion befindet. Eine schaltbare zusammensetzbare Funktion kann beispielsweise entweder den Status „aktiviert“ oder „nicht aktiviert“ haben. In einigen Fällen müssen Sie die in der Funktion „Compose“ verwendeten Labels für die Standardstatusbeschreibung überschreiben. Geben Sie dazu explizit die Labels für die Zustandsbeschreibung an, bevor Sie eine zusammensetzbare Funktion 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 vollständigen Inhalt eines Artikels anzeigen, den der Nutzer gerade liest:
Nutzende mit Anforderungen an Bedienungshilfen haben Schwierigkeiten, auf einem solchen Bildschirm zu navigieren. Um die Navigation zu erleichtern, geben Sie an, welche Elemente Überschriften sind. Im vorherigen Beispiel könnte jeder Unterabschnittstitel als Überschrift für die Barrierefreiheit definiert werden. Bei einigen Bedienungshilfen wie TalkBack können Nutzer direkt von Überschrift zu Überschrift wechseln.
In der Funktion „Compose“ geben Sie an, dass eine zusammensetzbare Funktion eine Überschrift ist. Dazu definieren Sie die Eigenschaft semantics
:
@Composable private fun Subsection(text: String) { Text( text = text, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.semantics { heading() } ) }
Benutzerdefinierte zusammensetzbare Funktionen verarbeiten
Wenn Sie bestimmte Material-Komponenten in Ihrer App durch benutzerdefinierte Versionen ersetzen, müssen Sie die Überlegungen zur Barrierefreiheit berücksichtigen.
Angenommen, Sie ersetzen das Material Checkbox
durch Ihre eigene Implementierung.
Sie könnten vergessen, den triStateToggleable
-Modifikator hinzuzufügen, der die Bedienungshilfen dieser Komponente verwaltet.
Als Faustregel gilt: Sehen Sie sich die Implementierung der Komponente in der Materialbibliothek an und ahmen Sie alle verfügbaren Bedienungshilfen nach. Außerdem solltest du im Gegensatz zu Modifizierern auf UI-Ebene intensiv die Foundation-Modifikatoren einsetzen, da diese die Barrierefreiheit bereits standardmäßig berücksichtigen.
Testen Sie die Implementierung Ihrer benutzerdefinierten Komponenten mit verschiedenen Bedienungshilfen, um ihr Verhalten zu überprüfen.
Weitere Informationen
- Barrierefreiheit:Diese grundlegenden Konzepte und Techniken, die bei der Entwicklung von Android-Apps üblich sind
- Accessible Apps erstellen:Wichtige Schritte, mit denen Sie die Barrierefreiheit Ihrer App verbessern können
- Prinzipien zur Verbesserung der Barrierefreiheit von Apps:Wichtige Prinzipien, die Sie bei der Verbesserung der Barrierefreiheit Ihrer App beachten sollten
- Test auf Barrierefreiheit:Testprinzipien und -tools für Android-Bedienungshilfen