Grundsätze zur Verbesserung der Barrierefreiheit von Apps (Ansichten)

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 actions 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. (Von View ü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. (Von View übernommen.)
  • Merkmale:Details zu jedem TriSwitch-Objekt, z. B. der Inhalt von Text, der darin angezeigt wird. (Von TextView übernommen.)
  • Statusinformationen:Beschreibung des aktuellen Status eines TriSwitch-Objekts, z. B. „checked“ (aktiviert) oder „unchecked“ (deaktiviert). (Von CompoundButton ü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:

Codelabs

Blogposts