Zasady dotyczące ułatwień dostępu w aplikacjach

Aby ułatwić użytkownikom ułatwienie dostępu, platforma Androida umożliwia utworzenie usługi ułatwień dostępu, która umożliwia prezentowanie treści z aplikacji użytkownikom oraz obsługę aplikacji w ich imieniu.

Android oferuje kilka systemowych usług ułatwień dostępu, między innymi:

  • TalkBack pomaga osobom niedowidzącym i niewidomym, Informuje o treściach syntezatorem głosu i wykonuje działania w aplikacji w odpowiedzi na gesty użytkownika.
  • Switch Access: pomaga osobom z niepełnosprawnością ruchową. Wyróżnia interaktywne elementy i wykonuje działania w odpowiedzi na naciśnięcie przycisku. Można w nim sterować za pomocą jednego lub dwóch przycisków.

Aby ułatwić osobom niepełnosprawnym korzystanie z Twojej aplikacji, musi ona być zgodna ze sprawdzonymi metodami opisanymi na tej stronie. Opiera się ona na wytycznych opisanych w artykule Zwiększanie dostępności aplikacji.

Każda z tych sprawdzonych metod opisanych w kolejnych sekcjach może jeszcze bardziej zwiększyć ułatwienia dostępu w aplikacji:

Oznaczanie elementów etykietami
Użytkownicy muszą być w stanie zrozumieć treść i przeznaczenie każdego interaktywnego i istotnego elementu UI w aplikacji.
Dodawanie działań związanych z ułatwieniami dostępu
Dodając działania związane z ułatwieniami dostępu, możesz umożliwić użytkownikom usług ułatwień dostępu wykonywanie najważniejszych czynności w Twojej aplikacji.
Rozszerzanie widżetów systemowych
Zamiast tworzyć własne widoki niestandardowe, wykorzystuj elementy widoku zawarte w platformie. Klasy widoku i widżetów platformy już udostępniają większość funkcji ułatwień dostępu potrzebnych aplikacji.
Używanie wskazówek innych niż kolor
Użytkownicy muszą być w stanie wyraźnie rozróżnić kategorie elementów w interfejsie. Aby to zrobić, odzwierciedlaj te różnice za pomocą wzorców i położenia oraz koloru.
Zwiększanie dostępności treści multimedialnych
Dodaj opisy do treści audio lub wideo w aplikacji, aby użytkownicy oglądający te treści nie musieli polegać wyłącznie na sygnałach wizualnych lub dźwiękowych.

Elementy etykiety

Ważne jest, aby zapewnić użytkownikom przydatne i opisowe etykiety każdego interaktywnego elementu interfejsu w aplikacji. Każda etykieta musi wyjaśniać znaczenie i przeznaczenie danego elementu. Czytniki ekranu, takie jak TalkBack, mogą odczytywać te etykiety użytkownikom.

W większości przypadków opis elementu interfejsu musisz podać w pliku zasobów układu, który zawiera ten element. Zwykle etykiety dodaje się za pomocą atrybutu contentDescription, jak opisano w przewodniku po ułatwianiu dostępu do aplikacji. Istnieje kilka innych metod oznaczania etykietami, które zostały opisane w sekcjach poniżej.

Elementy do edycji

Gdy dodajesz etykiety do elementów możliwych do edytowania, takich jak obiekty EditText, warto oprócz tego udostępnić czytnikom ekranu tekst zawierający przykład prawidłowych danych wejściowych w samym elemencie. W takich sytuacjach możesz użyć atrybutu android:hint, jak pokazano w tym fragmencie:

<!-- The hint text for en-US locale would be
     "Apartment, suite, or building". -->
<EditText
   android:id="@+id/addressLine2"
   android:hint="@string/aptSuiteBuilding" ... />

W tej sytuacji atrybut android:labelFor obiektu View musi być ustawiony na identyfikator elementu EditText. Więcej informacji znajdziesz w sekcji poniżej.

Pary elementów, w których jeden opisuje drugi

Często element EditText ma odpowiadający mu obiekt View, który opisuje, co użytkownicy muszą wpisać w elemencie EditText. Możesz wskazać tę relację, ustawiając atrybut android:labelFor obiektu View.

Przykład oznaczania takich par elementów etykietami znajdziesz we fragmencie kodu:


<!-- 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" ... />

Elementy w kolekcji

Gdy dodajesz etykiety do elementów kolekcji, każda etykieta musi być unikalna. Dzięki temu usługi ułatwień dostępu w systemie mogą odnosić się do dokładnie jednego elementu na ekranie podczas wypowiadania etykiety. Dzięki temu użytkownicy wiedzą, kiedy przełączają się w interfejsie lub przenoszą zaznaczenie na element, który już odkryli.

W szczególności umieść dodatkowy tekst lub informacje kontekstowe w elementach w ponownie użytych układach, np. w obiektach RecyclerView, aby każdy element podrzędny był jednoznacznie identyfikowany.

W tym celu ustaw opis treści w ramach implementacji adaptera, jak w tym fragmencie kodu:

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

Grupy powiązanych treści

Jeśli aplikacja wyświetla kilka elementów interfejsu, które tworzą grupę naturalną, np. szczegóły utworu lub atrybuty wiadomości, umieść je w kontenerze, który zwykle jest podklasą klasy ViewGroup. Ustaw atrybut android:screenReaderFocusable obiektu kontenera na true, a wartość atrybutu android:focusable każdego obiektu wewnętrznego na false. Dzięki temu usługi ułatwień dostępu mogą prezentować poszczególne opisy zawartości poszczególnych elementów jeden po drugim w jednym ogłoszeniu. Ta konsolidacja powiązanych elementów pomaga użytkownikom technologii wspomagających osoby z niepełnosprawnością skuteczniej znajdować informacje na ekranie.

Ten fragment kodu zawiera powiązane ze sobą fragmenty treści. Atrybut android:screenReaderFocusable elementu kontenera (wystąpienie obiektu ConstraintLayout) jest więc ustawiony na true, a atrybut android:focusable dla każdego z nich TextView:false

<!-- 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>

Ponieważ usługi ułatwień dostępu wypowiadają opisy elementów wewnętrznych w jednej wypowiedzi, każdy z nich powinien być jak najkrótszy, a jednocześnie przekazywać przeznaczenie elementu.

Uwaga: zasadniczo nie należy tworzyć opisu treści dla grupy przez agregowanie tekstów jej elementów podrzędnych. W rezultacie opis grupy będzie krótszy, a gdy tekst w podrzędnym się zmieni, opis grupy może już nie odpowiadać temu, który jest widoczny.

Na listach lub w kontekście siatki czytnik ekranu może skonsolidować tekst węzłów tekstowych listy lub podrzędnych elementów siatki. Najlepiej nie wprowadzać zmian w tym ogłoszeniu.

Grupy zagnieżdżone

Jeśli interfejs aplikacji zawiera wielowymiarowe informacje, np. listę dni festiwali, użyj atrybutu android:screenReaderFocusable w kontenerach grupy wewnętrznej. Ten schemat oznaczania etykietami zapewnia dobrą równowagę między liczbą ogłoszeń potrzebnych do wykrycia zawartości ekranu a długością każdego ogłoszenia.

Ten fragment kodu przedstawia jedną metodę oznaczania grup etykietami w większych grupach:

<!-- 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>

Nagłówki w tekście

Niektóre aplikacje używają nagłówków do podsumowania grup tekstu wyświetlanego na ekranie. Jeśli określony element View reprezentuje nagłówek, możesz określić jego przeznaczenie na potrzeby usług ułatwień dostępu, ustawiając atrybut android:accessibilityHeading tego elementu na true.

Użytkownicy usług ułatwień dostępu mogą przełączać się między nagłówkami zamiast między akapitami czy między słowami. Ta elastyczność ułatwia nawigację po tekście.

Tytuły paneli ułatwień dostępu

W Androidzie 9 (poziom interfejsu API 28) i nowszych możesz podawać tytuły przesuwane na ekranie, które są łatwe w użyciu. W przypadku ułatwień dostępu panel to wizualnie wyróżniająca się część okna, np. zawartość fragmentu. Aby usługi ułatwień dostępu mogły rozumieć działanie okienne, nadaj im opisowe tytuły. Usługi ułatwień dostępu mogą wtedy dostarczać użytkownikom bardziej szczegółowe informacje, gdy zmienia się wygląd lub treść panelu.

Aby określić tytuł panelu, użyj atrybutu android:accessibilityPaneTitle, jak pokazano w tym fragmencie:

<!-- 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" ... />

Elementy dekoracyjne

Jeśli element w interfejsie służy tylko do celów związanych z wizualnymi odstępami lub wyglądem, ustaw jego atrybut android:importantForAccessibility na "no".

Dodawanie działań związanych z ułatwieniami dostępu

Ważne jest, aby użytkownicy usług ułatwień dostępu mogli łatwo wykonywać wszystkie czynności w obrębie aplikacji. Jeśli na przykład użytkownik może przesunąć palcem po elemencie na liście, to działanie może być również ujawnione usługom ułatwień dostępu, dzięki czemu będą mogli wykonać ten sam proces w inny sposób.

Udostępnij wszystkie działania

Użytkownik korzystający z TalkBack, Voice Access lub Switch Access może potrzebować innych sposobów wykonywania pewnych działań w aplikacji. W przypadku działań związanych z gestami, takimi jak przeciąganie i upuszczanie czy przesuwania, aplikacja może prezentować te działania w sposób dostępny dla użytkowników usług ułatwień dostępu.

Korzystając z działań związanych z ułatwieniami dostępu, aplikacja może udostępniać użytkownikom alternatywne sposoby wykonywania określonych czynności.

Jeśli np. aplikacja umożliwia użytkownikom przesuwanie palcem po elemencie, możesz też zaprezentować tę funkcję, używając niestandardowego działania ułatwień dostępu:

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

Najlepiej, aby nowa klasa TriSwitch rozwijała się bezpośrednio z klasy Switch. Dzięki temu platforma ułatwień dostępu na Androidzie zapewnia większość funkcji ułatwień dostępu, których potrzebuje klasa TriSwitch:

  • Działania związane z ułatwieniami dostępu: informacje dla systemu o tym, jak usługi ułatwień dostępu mogą emulować każde możliwe dane wejściowe użytkownika wykonywane na obiekcie TriSwitch. (Odziedziczone z grupy View).
  • Zdarzenia ułatwień dostępu: informacje dla usług ułatwień dostępu o wszystkich możliwych sposobach zmiany wyglądu obiektu TriSwitch podczas odświeżania lub aktualizowania ekranu. (Odziedziczone z grupy View).
  • Cechy: szczegółowe informacje o każdym obiekcie TriSwitch, np. zawartość wyświetlanego tekstu. (Odziedziczone z grupy TextView).
  • Informacje o stanie: opis bieżącego stanu obiektu TriSwitch, np. „zaznaczony” lub „odznaczony”. (Odziedziczone z grupy CompoundButton).
  • Tekstowy opis stanu: tekstowy opis stanów w poszczególnych stanach. (Odziedziczone z grupy Switch).

To zachowanie w przypadku Switch i jego nadrzędnych klas jest prawie takie samo w przypadku obiektów TriSwitch. Dlatego w implementacji możesz skupić się na zwiększeniu liczby możliwych stanów z 2 do 3.

Definiowanie zdarzeń niestandardowych

Rozbudowywanie widżetu systemowego może spowodować zmianę sposobu interakcji użytkowników z tym widżetem. Ważne jest zdefiniowanie tych zmian interakcji, aby usługi ułatwień dostępu mogły aktualizować widżet aplikacji tak, jakby użytkownik bezpośrednio wchodził z nim w interakcję.

Ogólna zasada jest taka, że w przypadku każdego zastąpienia wywołania zwrotnego na podstawie widoku trzeba też ponownie zdefiniować odpowiednie działanie ułatwień dostępu, zastępując wartość ViewCompat.replaceAccessibilityAction(). W testach aplikacji możesz sprawdzić działanie tych zdefiniowanych działań, wywołując metodę ViewCompat.performAccessibilityAction().

Jak ta zasada może działać w przypadku obiektów TriSwitch

W przeciwieństwie do zwykłego obiektu Switch kliknięcie obiektu TriSwitch zmienia się w 3 możliwe stany. Dlatego musisz zaktualizować odpowiednie działanie związane z ułatwieniami dostępu w usłudze ACTION_CLICK:

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;
    }
}

Używaj wskazówek innych niż kolor

Aby pomóc użytkownikom z zaburzeniami rozpoznawania barw, do rozróżnienia elementów interfejsu na ekranach aplikacji używaj wskazówek innych niż kolor. Techniki te mogą obejmować stosowanie różnych kształtów lub rozmiarów, dodawanie tekstu lub wzorów wizualnych albo dodawanie sygnałów dźwiękowych lub dotykowych, aby zaznaczyć różnice między elementami.

Rysunek 1 przedstawia 2 wersje aktywności. Jedna wersja używa tylko koloru do rozróżnienia 2 możliwych działań w przepływie pracy. Druga wersja korzysta ze sprawdzonej metody polegającej na dodaniu do koloru kształtów i tekstu, aby podkreślić różnice między tymi 2 opcjami:

Rysunek 1. Przykłady tworzenia elementów interfejsu tylko z użyciem koloru (po lewej) oraz z użyciem koloru, kształtów i tekstu (po prawej).

Zwiększ dostępność treści multimedialnych

Jeśli tworzysz aplikację, która zawiera treści multimedialne, np. klipy wideo lub nagrania dźwiękowe, spróbuj pomóc użytkownikom z różnymi potrzebami związanymi z ułatwieniami dostępu, aby zrozumieć te treści. W szczególności zachęcamy do:

  • Zawierają elementy sterujące, które pozwalają użytkownikom wstrzymywać i zatrzymywać multimedia, zmieniać głośność oraz włączać napisy.
  • Jeśli film zawiera informacje niezbędne do ukończenia przepływu pracy, udostępnij te same treści w innym formacie, np. w transkrypcji.

Dodatkowe materiały

Więcej informacji o ułatwieniach dostępu w aplikacji znajdziesz w tych dodatkowych materiałach:

Ćwiczenia z programowania

Posty na blogu