Konzepte und Jetpack Compose-Implementierung
Um Nutzern mit Beeinträchtigungen zu helfen, können Sie mit dem Android-Framework eine Bedienungshilfe erstellen, die Inhalte aus Apps für Nutzer präsentieren und Apps in ihrem Namen bedienen kann.
Android bietet mehrere Systemdienste für Barrierefreiheit, darunter die folgenden:
- TalkBack: Diese Funktion hilft Menschen mit Sehbehinderung oder eingeschränktem Sehvermögen. Es kündigt Inhalte über eine synthetische Stimme an und führt Aktionen in einer App als Reaktion auf Nutzergesten aus.
- Schalterzugriff: Diese Funktion ist für Menschen mit motorischen Beeinträchtigungen hilfreich. Es werden interaktive Elemente hervorgehoben und Aktionen ausgeführt, wenn der Nutzer eine Taste drückt. Das Gerät lässt sich über einen oder zwei Tasten steuern.
Damit Menschen mit Behinderung Ihre App problemlos nutzen können, muss sie den Best Practices auf dieser Seite entsprechen. Diese basieren auf den Richtlinien unter Apps barrierefreier gestalten.
Labelelemente
Es ist wichtig, dass Sie Nutzern nützliche und aussagekräftige Labels für jedes interaktive UI-Element in Ihrer App zur Verfügung stellen. Jedes Label muss die Bedeutung und den Zweck eines bestimmten Elements erklären. Screenreader wie TalkBack können diese Labels Nutzern ansagen.
In den meisten Fällen geben Sie die Beschreibung eines UI-Elements in der Layoutressourcendatei an, die das Element enthält. Normalerweise fügen Sie Labels mit dem Attribut contentDescription hinzu, wie im Leitfaden Apps barrierefreier gestalten beschrieben. In den folgenden Abschnitten werden verschiedene andere Labeling-Techniken beschrieben.
Bearbeitbare Elemente
Beim Beschriften bearbeitbarer Elemente wie EditText-Objekte ist es hilfreich, neben der Bereitstellung dieses Beispieltexts für Screenreader auch Text anzuzeigen, der ein Beispiel für eine gültige Eingabe im Element selbst enthält. In diesen Fällen können Sie das Attribut android:hint verwenden, wie im folgenden Snippet gezeigt:
<!-- The hint text for en-US locale would be "Apartment, suite, or building". --> <EditText android:id="@+id/addressLine2" android:hint="@string/aptSuiteBuilding" ... />
In diesem Fall muss für das View-Objekt das Attribut android:labelFor auf die ID des EditText-Elements festgelegt werden. Weitere Informationen finden Sie im folgenden Abschnitt.
Paare von Elementen, bei denen eines das andere beschreibt
Ein EditText-Element hat in der Regel ein entsprechendes View-Objekt, das beschreibt, was Nutzer in das EditText-Element eingeben müssen. Sie können diese Beziehung angeben, indem Sie das Attribut android:labelFor des View-Objekts festlegen.
Ein Beispiel für die Kennzeichnung solcher Elementpaare finden Sie im folgenden Snippet:
<!-- Label text for en-US locale would be "Username:" --> <TextView android:id="@+id/usernameLabel" ... android:text="@string/username" android:labelFor="@+id/usernameEntry" /> <EditText android:id="@+id/usernameEntry" ... /> <!-- Label text for en-US locale would be "Password:" --> <TextView android:id="@+id/passwordLabel" ... android:text="@string/password android:labelFor="@+id/passwordEntry" /> <EditText android:id="@+id/passwordEntry" android:inputType="textPassword" ... />
Elemente in einer Sammlung
Wenn Sie den Elementen einer Sammlung Labels hinzufügen, muss jedes Label eindeutig sein. So können die Bedienungshilfen des Systems beim Ausgeben eines Labels auf genau ein Element auf dem Bildschirm verweisen. So wissen Nutzer, wann sie durch die Benutzeroberfläche navigieren oder den Fokus auf ein Element legen, das sie bereits entdeckt haben.
Fügen Sie insbesondere zusätzlichen Text oder Kontextinformationen in Elemente in wiederverwendeten Layouts ein, z. B. in RecyclerView-Objekte, damit jedes untergeordnete Element eindeutig identifiziert wird.
Legen Sie dazu die Inhaltsbeschreibung als Teil Ihrer Adapterimplementierung fest, wie im folgenden Code-Snippet gezeigt:
Kotlin
data class MovieRating(val title: String, val starRating: Integer) class MyMovieRatingsAdapter(private val myData: Array<MovieRating>): RecyclerView.Adapter<MyMovieRatingsAdapter.MyRatingViewHolder>() { class MyRatingViewHolder(val ratingView: ImageView) : RecyclerView.ViewHolder(ratingView) override fun onBindViewHolder(holder: MyRatingViewHolder, position: Int) { val ratingData = myData[position] holder.ratingView.contentDescription = "Movie ${position}: " + "${ratingData.title}, ${ratingData.starRating} stars" } }
Java
public class MovieRating { private String title; private int starRating; // ... public String getTitle() { return title; } public int getStarRating() { return starRating; } } public class MyMovieRatingsAdapter extends RecyclerView.Adapter<MyAdapter.MyRatingViewHolder> { private MovieRating[] myData; public static class MyRatingViewHolder extends RecyclerView.ViewHolder { public ImageView ratingView; public MyRatingViewHolder(ImageView iv) { super(iv); ratingView = iv; } } @Override public void onBindViewHolder(MyRatingViewHolder holder, int position) { MovieRating ratingData = myData[position]; holder.ratingView.setContentDescription("Movie " + position + ": " + ratingData.getTitle() + ", " + ratingData.getStarRating() + " stars") } }
Gruppen ähnlicher Inhalte
Wenn in Ihrer App mehrere UI-Elemente angezeigt werden, die eine natürliche Gruppe bilden, z. B. Details zu einem Song oder Attribute einer Nachricht, ordnen Sie diese Elemente in einem Container an, der in der Regel eine abgeleitete Klasse von ViewGroup ist. Legen Sie das Attribut android:screenReaderFocusable des Containerobjekts auf true und das Attribut android:focusable jedes inneren Objekts auf false fest. So können Bedienungshilfen die Inhaltsbeschreibungen der inneren Elemente nacheinander in einer einzigen Ansage präsentieren.
Durch diese Zusammenfassung verwandter Elemente können Nutzer von Hilfstechnologien die Informationen auf dem Bildschirm effizienter erfassen.
Das folgende Snippet enthält inhaltliche Elemente, die sich aufeinander beziehen. Das Containerelement, eine Instanz von ConstraintLayout, hat das Attribut android:screenReaderFocusable auf true festgelegt und die inneren TextView-Elemente haben jeweils das Attribut android:focusable auf false festgelegt:
<!-- In response to a single user interaction, accessibility services announce both the title and the artist of the song. --> <ConstraintLayout android:id="@+id/song_data_container" ... android:screenReaderFocusable="true"> <TextView android:id="@+id/song_title" ... android:focusable="false" android:text="@string/my_song_title" /> <TextView android:id="@+id/song_artist" android:focusable="false" android:text="@string/my_songwriter" /> </ConstraintLayout>
Da Barrierefreiheitsdienste die Beschreibungen der inneren Elemente in einem einzigen Satz ausgeben, ist es wichtig, jede Beschreibung so kurz wie möglich zu halten und gleichzeitig die Bedeutung des Elements zu vermitteln.
Hinweis:Im Allgemeinen sollten Sie keine Inhaltsbeschreibung für eine Gruppe erstellen, indem Sie den Text der untergeordneten Elemente zusammenfassen. Dadurch wird die Beschreibung der Gruppe anfällig. Wenn sich der Text eines untergeordneten Elements ändert, stimmt die Beschreibung der Gruppe möglicherweise nicht mehr mit dem sichtbaren Text überein.
In einer Liste oder einem Raster kann ein Screenreader den Text der untergeordneten Textknoten eines Listen- oder Rasterelements zusammenfassen. Es ist am besten, diese Mitteilung nicht zu ändern.
Verschachtelte Gruppen
Wenn die Benutzeroberfläche Ihrer App mehrdimensionale Informationen wie eine tagesaktuelle Liste von Festivalveranstaltungen präsentiert, verwenden Sie das Attribut android:screenReaderFocusable für die inneren Gruppencontainer. Dieses Kennzeichnungsschema bietet ein gutes Gleichgewicht zwischen der Anzahl der erforderlichen Ansagen, um den Inhalt des Bildschirms zu erkennen, und der Länge jeder Ansage.
Das folgende Code-Snippet zeigt eine Methode zum Kennzeichnen von Gruppen innerhalb größerer Gruppen:
<!-- In response to a single user interaction, accessibility services announce the events for a single stage only. --> <ConstraintLayout android:id="@+id/festival_event_table" ... > <ConstraintLayout android:id="@+id/stage_a_event_column" android:screenReaderFocusable="true"> <!-- UI elements that describe the events on Stage A. --> </ConstraintLayout> <ConstraintLayout android:id="@+id/stage_b_event_column" android:screenReaderFocusable="true"> <!-- UI elements that describe the events on Stage B. --> </ConstraintLayout> </ConstraintLayout>
Überschriften im Text
Einige Apps verwenden Überschriften, um Textgruppen auf dem Bildschirm zusammenzufassen. Wenn ein bestimmtes View-Element eine Überschrift darstellt, können Sie seinen Zweck für Bedienungshilfen angeben, indem Sie das Attribut android:accessibilityHeading des Elements auf true setzen.
Nutzer von Bedienungshilfen können wählen, ob sie zwischen Überschriften statt zwischen Absätzen oder Wörtern navigieren möchten. Diese Flexibilität verbessert die Textnavigation.
Titel von Bedienungshilfenbereichen
Unter Android 9 (API-Level 28) und höher können Sie barrierefreie Titel für die Bereiche eines Bildschirms angeben. Aus Gründen der Barrierefreiheit ist ein Bereich ein visuell abgegrenzter Teil eines Fensters, z. B. der Inhalt eines Fragments. Damit Bedienungshilfen das fensterähnliche Verhalten eines Bereichs nachvollziehen können, sollten Sie den Bereichen Ihrer App aussagekräftige Titel geben. Barrierefreiheitsdienste können Nutzern dann detailliertere Informationen liefern, wenn sich das Erscheinungsbild oder der Inhalt eines Bereichs ändert.
Verwenden Sie das Attribut android:accessibilityPaneTitle, um den Titel eines Bereichs anzugeben, wie im folgenden Snippet gezeigt:
<!-- Accessibility services receive announcements about content changes that are scoped to either the "shopping cart view" section (top) or "browse items" section (bottom) --> <MyShoppingCartView android:id="@+id/shoppingCartContainer" android:accessibilityPaneTitle="@string/shoppingCart" ... /> <MyShoppingBrowseView android:id="@+id/browseItemsContainer" android:accessibilityPaneTitle="@string/browseProducts" ... />
Dekorative Elemente
Wenn ein Element in Ihrer Benutzeroberfläche nur für die visuelle Gestaltung oder das visuelle Erscheinungsbild vorhanden ist, setzen Sie das Attribut android:importantForAccessibility auf "no".
Aktionen für Bedienungshilfen hinzufügen
Es ist wichtig, dass Nutzer von Bedienungshilfen alle User Flows in Ihrer App problemlos ausführen können. Wenn ein Nutzer beispielsweise auf einem Element in einer Liste wischen kann, sollte diese Aktion auch für Bedienungshilfen verfügbar sein, damit Nutzer eine alternative Möglichkeit haben, denselben User Flow auszuführen.
Alle Aktionen zugänglich machen
Nutzer von TalkBack, Voice Access oder dem Schalterzugriff benötigen möglicherweise alternative Möglichkeiten, um bestimmte Nutzerflows in der App auszuführen. Bei Aktionen, die mit Gesten wie Drag-and-drop oder Wischen verknüpft sind, kann Ihre App die Aktionen so bereitstellen, dass sie für Nutzer von Bedienungshilfen zugänglich sind.
Mit Barrierefreiheitsaktionen kann die App Nutzern alternative Möglichkeiten bieten, eine Aktion auszuführen.
Wenn Nutzer in Ihrer App beispielsweise auf einem Element wischen können, können Sie die Funktion auch über eine benutzerdefinierte Bedienungshilfeaktion verfügbar machen:
Kotlin
ViewCompat.addAccessibilityAction( // View to add accessibility action itemView, // Label surfaced to user by an accessibility service getText(R.id.archive) ) { _, _ -> // Same method executed when swiping on itemView archiveItem() true }
Java
ViewCompat.addAccessibilityAction( // View to add accessibility action itemView, // Label surfaced to user by an accessibility service getText(R.id.archive), (view, arguments) -> { // Same method executed when swiping on itemView archiveItem(); return true; } );
With the custom accessibility action implemented, users can access the action through the actions menu.
Make available actions understandable
When a view supports actions such as touch & hold, an accessibility service such as TalkBack announces it as "Double tap and hold to long press."
This generic announcement doesn't give the user any context about what a touch & hold action does.
To make this announcement more descriptive, you can replace the accessibility action’s announcement like so:
Kotlin
ViewCompat.replaceAccessibilityAction( // View that contains touch & hold action itemView, AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_LONG_CLICK, // Announcement read by TalkBack to surface this action getText(R.string.favorite), null )
Java
ViewCompat.replaceAccessibilityAction( // View that contains touch & hold action itemView, AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_LONG_CLICK, // Announcement read by TalkBack to surface this action getText(R.string.favorite), null );
This results in TalkBack announcing "Double tap and hold to favorite," helping users understand the purpose of the action.
Extend system widgets
Note: When you design your app's UI, use or extend
system-provided widgets that are as far down Android's class hierarchy as
possible. System-provided widgets that are far down the hierarchy already
have most of the accessibility capabilities your app needs. It's easier
to extend these system-provided widgets than to create your own from the more
generic View,
ViewCompat,
Canvas, and
CanvasCompat
classes.
If you must extend View or Canvas directly, which
might be necessary for a highly customized experience or a game level, see
Make custom views more
accessible.
This section uses the example of implementing a special type of
Switch called TriSwitch while following
best practices around extending system widgets. A TriSwitch
object works similarly to a Switch object, except that each instance of
TriSwitch allows the user to toggle among three possible states.
Extend from far down the class hierarchy
The Switch object inherits from several framework UI classes in its hierarchy:
View ↳ TextView ↳ Button ↳ CompoundButton ↳ Switch
Die neue Klasse TriSwitch sollte direkt von der Klasse Switch abgeleitet werden. So bietet das Android-Framework für Bedienungshilfen die meisten Bedienungshilfen, die die Klasse TriSwitch benötigt:
- Barrierefreiheitsaktionen:Informationen für das System dazu, wie Barrierefreiheitsdienste jede mögliche Nutzereingabe emulieren können, die für ein
TriSwitch-Objekt ausgeführt wird. (VonViewübernommen.) - Bedienungshilfe-Ereignisse:Informationen für Bedienungshilfen zu allen möglichen Änderungen, die am Erscheinungsbild eines
TriSwitch-Objekts vorgenommen werden können, wenn der Bildschirm aktualisiert wird. (VonViewübernommen.) - Merkmale:Details zu jedem
TriSwitch-Objekt, z. B. der Inhalt von Text, der darin angezeigt wird. (VonTextViewübernommen.) - Statusinformationen:Beschreibung des aktuellen Status eines
TriSwitch-Objekts, z. B. „checked“ (aktiviert) oder „unchecked“ (deaktiviert). (VonCompoundButtonübernommen.) - Textbeschreibung des Status:Textbasierte Erklärung der Bedeutung der einzelnen Status. (Von
Switchübernommen.)
Dieses Verhalten von Switch und seinen Superklassen ist fast dasselbe wie das Verhalten von TriSwitch-Objekten. Daher kann sich Ihre Implementierung darauf konzentrieren, die Anzahl der möglichen Status von zwei auf drei zu erhöhen.
Benutzerdefinierte Ereignisse definieren
Wenn Sie ein System-Widget erweitern, ändern Sie wahrscheinlich einen Aspekt der Interaktion von Nutzern mit diesem Widget. Es ist wichtig, diese Interaktionsänderungen zu definieren, damit Dienste zur Verbesserung der Barrierefreiheit das Widget Ihrer App so aktualisieren können, als ob der Nutzer direkt mit dem Widget interagiert.
Eine allgemeine Richtlinie besagt, dass Sie für jeden auf Ansichten basierenden Callback, den Sie überschreiben, auch die entsprechende Barrierefreiheitsaktion neu definieren müssen, indem Sie ViewCompat.replaceAccessibilityAction() überschreiben.
In den Tests Ihrer App können Sie das Verhalten dieser neu definierten Aktionen validieren, indem Sie ViewCompat.performAccessibilityAction() aufrufen.
Anwendung dieses Prinzips auf TriSwitch-Objekte
Im Gegensatz zu einem normalen Switch-Objekt werden durch Tippen auf ein TriSwitch-Objekt drei mögliche Status durchlaufen. Daher muss die entsprechende ACTION_CLICK-Bedienungshilfenaktion aktualisiert werden:
Kotlin
class TriSwitch(context: Context) : Switch(context) { // 0, 1, or 2 var currentState: Int = 0 private set init { updateAccessibilityActions() } private fun updateAccessibilityActions() { ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK, action-label) { view, args -> moveToNextState() }) } private fun moveToNextState() { currentState = (currentState + 1) % 3 } }
Java
public class TriSwitch extends Switch { // 0, 1, or 2 private int currentState; public int getCurrentState() { return currentState; } public TriSwitch() { updateAccessibilityActions(); } private void updateAccessibilityActions() { ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK, action-label, (view, args) -> moveToNextState()); } private void moveToNextState() { currentState = (currentState + 1) % 3; } }
Zusätzliche Ressourcen
Weitere Informationen zur Barrierefreiheit Ihrer App finden Sie in den folgenden zusätzlichen Ressourcen: