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

Aby ułatwić korzystanie z urządzeń użytkownikom z niepełnosprawnościami, platforma Android umożliwia tworzenie usług ułatwień dostępu, które mogą prezentować treści z aplikacji i obsługiwać je w imieniu użytkowników.

Android udostępnia kilka systemowych usług ułatwień dostępu, w tym:

  • TalkBack: pomaga osobom niedowidzącym i niewidomym. Odczytuje treści za pomocą syntezatora mowy i wykonuje działania w aplikacji w odpowiedzi na gesty użytkownika.
  • Switch Access: pomaga osobom z niepełnosprawnością ruchową. Podświetla elementy interaktywne i wykonuje działania w odpowiedzi na naciśnięcie przycisku przez użytkownika. Umożliwia sterowanie urządzeniem za pomocą tylko 1 lub 2 przycisków.

Aby osoby z niepełnosprawnościami mogły bez problemu korzystać z Twojej aplikacji, musi ona być zgodna ze sprawdzonymi metodami opisanymi na tej stronie, które bazują na wytycznych opisanych w artykule Ułatwianie dostępu do aplikacji.

Każda z tych sprawdzonych metod, opisanych w kolejnych sekcjach, może dodatkowo zwiększyć dostępność aplikacji:

Elementy etykiety
Użytkownicy muszą rozumieć treść i cel każdego interaktywnego i istotnego elementu interfejsu 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 w aplikacji najważniejszych działań.
Korzystanie z wbudowanych funkcji ułatwień dostępu
Domyślnie oferuje wiele funkcji ułatwień dostępu. Skorzystaj z wstępnie zdefiniowanych zachowań związanych z ułatwieniami dostępu, aby zapewnić dostępność komponentów przy niewielkim lub zerowym nakładzie pracy. Compose udostępnia też sposoby obsługi bardziej szczegółowych wymagań dotyczących ułatwień dostępu, które nie są objęte funkcjami domyślnymi.
Używaj innych wskazówek niż kolor
Użytkownicy muszą mieć możliwość wyraźnego odróżniania kategorii elementów w interfejsie. Aby to zrobić, używaj wzorów i położenia, a także koloru, aby wyrazić te różnice.
Ułatwianie dostępu do treści multimedialnych
Dodaj opisy do treści wideo lub audio w aplikacji, aby użytkownicy korzystający z tych treści nie musieli polegać wyłącznie na wskazówkach wizualnych lub dźwiękowych.

Elementy etykiety

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

W większości przypadków interfejsy API Compose i Material mają domyślną obsługę ułatwień dostępu. Jeśli jednak musisz ręcznie określić właściwości semantyczne elementu interfejsu, użyj modyfikatora semantics i właściwości contentDescription. Więcej informacji o semantyce znajdziesz w sekcji Semantyka.

W sekcjach poniżej opisujemy kilka innych technik etykietowania.

Elementy, które można edytować

Podczas oznaczania elementów możliwych do edytowania, takich jak pola tekstowe, warto wyświetlać tekst, który zawiera przykład prawidłowych danych wejściowych w samym elemencie, a także udostępniać ten tekst czytnikom ekranu. W takich sytuacjach możesz użyć tekstu zastępczego, zwanego też tekstem podpowiedzi.

W tym przykładzie element TextField ma parametr placeholder, który zawiera tekst podpowiedzi.

val usernameState = rememberTextFieldState()
TextField(
    state = usernameState,
    lineLimits = TextFieldLineLimits.SingleLine,
    placeholder = { Text("Enter Username") }
)

Często pole tekstowe ma też odpowiednią etykietę opisową, która informuje użytkowników, co muszą wpisać.

W tym przykładzie element TextField ma parametr label, który zawiera opis ułatwień dostępu.

TextField(
    state = rememberTextFieldState(initialText = "Hello"),
    label = { Text("Label") }
)

Więcej informacji o tekście i danych wejściowych użytkownika znajdziesz w artykule Konfigurowanie pól tekstowych.

Elementy w kolekcji

Podczas dodawania etykiet do elementów kolekcji każda etykieta musi być niepowtarzalna. Dzięki temu usługi ułatwień dostępu w systemie mogą odwoływać się do dokładnie jednego elementu na ekranie podczas ogłaszania etykiety. Dzięki temu użytkownicy wiedzą, kiedy przechodzą między elementami interfejsu lub kiedy przenoszą fokus na element, który już odkryli.

Jeśli na przykład masz LazyColumn lub LazyRow, użyj modyfikatora semantics, aby przypisać niepowtarzalny collectionItemInfo do każdego elementu, jak pokazano w tym fragmencie:

MilkyWayList(
    modifier = Modifier
        .semantics {
            collectionInfo = CollectionInfo(
                rowCount = milkyWay.count(),
                columnCount = 1
            )
        }
) {
    milkyWay.forEachIndexed { index, text ->
        Text(
            text = text,
            modifier = Modifier.semantics {
                collectionItemInfo =
                    CollectionItemInfo(index, 0, 0, 0)
            }
        )
    }
}

Więcej informacji o właściwościach semantycznych list i siatek znajdziesz w artykule Informacje o liście i elementach.

Grupy powiązanych treści

Jeśli aplikacja wyświetla kilka elementów interfejsu, które tworzą naturalną grupę, np. szczegóły utworu lub atrybuty wiadomości, umieść te elementy w kontenerze nadrzędnym (np. Column, Row lub Box). Użyj modyfikatora semantics kontenera nadrzędnego, aby ustawić mergeDescendants na true.

Dzięki temu usługi ułatwień dostępu mogą prezentować opisy zawartości elementów wewnętrznych jeden po drugim w jednym komunikacie. Konsolidacja powiązanych elementów pomaga użytkownikom technologii wspomagających osoby z niepełnosprawnością skuteczniej odkrywać informacje na ekranie.

W poniższym fragmencie funkcji kompozycyjnej Row użyto jako kontenera nadrzędnego. W tagu Row znajdują się powiązane elementy, które wyświetlają metadane posta na blogu – awatar autora, jego imię i nazwisko oraz szacowany czas czytania. Ustawienie mergeDescendants na true grupuje te elementy wewnętrzne, dzięki czemu usługi ułatwień dostępu mogą traktować je jako jedną jednostkę.

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

Gdy grupujesz powiązane elementy, jak w poprzednim przykładzie, spraw, aby interaktywny był tylko kontener nadrzędny. Unikaj dodawania modyfikatorów clickable lub focusable do wewnętrznych elementów podrzędnych. Zamiast tego zastosuj modyfikatory do nadrzędnego elementu Row lub Column.

Usługi ułatwień dostępu odczytują opisy elementów wewnętrznych w jednym komunikacie, dlatego ważne jest, aby każdy opis był jak najkrótszy, ale jednocześnie przekazywał znaczenie elementu.

Uwaga: podczas tworzenia opisu treści grupy unikaj agregowania tekstu jej elementów podrzędnych. W takim przypadku opis grupy staje się podatny na uszkodzenia, a gdy tekst elementu podrzędnego ulegnie zmianie, opis grupy może już nie pasować do widocznego tekstu.

W kontekście listy lub siatki czytnik ekranu może łączyć tekst węzłów tekstowych elementów podrzędnych listy lub siatki. Najlepiej nie modyfikować tego ogłoszenia.

Więcej informacji o scalaniu semantyki znajdziesz w artykule Scalanie i czyszczenie.

Nagłówki w tekście

Niektóre aplikacje używają nagłówków do podsumowywania grup tekstu wyświetlanych na ekranie. Jeśli dany element reprezentuje nagłówek, możesz wskazać jego przeznaczenie dla usług ułatwień dostępu, ustawiając właściwość heading w modyfikatorze semantics.

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

Użytkownicy usług ułatwień dostępu mogą przechodzić między nagłówkami zamiast między akapitami lub słowami. Ta elastyczność poprawia nawigację tekstową.

Więcej informacji o właściwości heading semantics znajdziesz w artykule Nagłówki.

Tytuły paneli ułatwień dostępu

W Androidzie 9 (API na poziomie 28) i nowszych wersjach możesz podać tytuły paneli ekranu, które są przyjazne dla osób z niepełnosprawnością. W celu ułatwienia dostępu panel to wizualnie odrębna część okna.

Aby usługi ułatwień dostępu mogły zrozumieć zachowanie panelu podobne do okna, nadaj panelom aplikacji opisowe tytuły. Usługi ułatwień dostępu mogą wtedy przekazywać użytkownikom bardziej szczegółowe informacje, gdy zmieni się wygląd lub zawartość panelu.

ShareSheet(
    message = "Choose how to share this photo",
    modifier = Modifier
        .fillMaxWidth()
        .align(Alignment.TopCenter)
        .semantics { paneTitle = "New bottom sheet" }
)

Więcej informacji o właściwości semantycznej paneTitle znajdziesz w sekcji Komponenty podobne do okien.

Elementy dekoracyjne

Jeśli element interfejsu istnieje tylko w celu zapewnienia odstępu lub wyglądu, ustaw odpowiednie właściwości elementu, aby wskazać, że usługi ułatwień dostępu mogą go zignorować.

W przypadku funkcji kompozycyjnych Image lub Icon ustaw contentDescription = null. W przypadku innych elementów dekoracyjnych, które nie zapewniają kontekstu ani funkcjonalności, możesz użyć hideFromAccessibility. Ta właściwość semantyczna informuje usługi ułatwień dostępu, aby zignorowały element.

Jeśli interaktywny element kompozycyjny zawiera dekoracyjne, nieinteraktywne elementy podrzędne, użyj clearAndSetSemantics, aby usługi ułatwień dostępu nie przechodziły przez te elementy. Pamiętaj, że atrybut clearAndSetSemantics całkowicie usuwa domyślną semantykę elementu i jego elementów podrzędnych. Umożliwia to zdefiniowanie nowego, ujednoliconego elementu ułatwień dostępu. Zwykle używa się tego podejścia w przypadku złożonych komponentów niestandardowych.

W przykładzie poniżej elementy IconText są dekoracyjnymi elementami podrzędnymi w niestandardowym przełączniku. Aby uniemożliwić usługom ułatwień dostępu przechodzenie przez te elementy podrzędne pojedynczo, możesz wyczyścić ich semantykę za pomocą clearAndSetSemantics na elemencie nadrzędnym Row. Informuje to usługi ułatwień dostępu, że cały element Row ma być traktowany jako przełącznik, po którym można się poruszać:

// Developer might intend this to be a toggleable.
// Using `clearAndSetSemantics`, on the Row, a clickable modifier is applied,
// a custom description is set, and a Role is applied.

@Composable
fun FavoriteToggle() {
    val checked = remember { mutableStateOf(true) }
    Row(
        modifier = Modifier
            .toggleable(
                value = checked.value,
                onValueChange = { checked.value = it }
            )
            .clearAndSetSemantics {
                stateDescription = if (checked.value) "Favorited" else "Not favorited"
                toggleableState = ToggleableState(checked.value)
                role = Role.Switch
            },
    ) {
        Icon(
            imageVector = Icons.Default.Favorite,
            contentDescription = null // not needed here

        )
        Text("Favorite?")
    }
}

Więcej informacji o czyszczeniu semantyki znajdziesz w artykule Czyszczenie i ustawianie semantyki.

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

Ważne jest, aby użytkownicy usług ułatwień dostępu mogli przejść wszystkie ścieżki użytkownika w Twojej aplikacji.

Jeśli interakcja z kompozycją niestandardową zmienia stan aplikacji w nieoczywisty sposób, dodaj opisowe etykiety standardowych działań związanych z kliknięciem, używając parametrów takich jak onClickLabel lub onLongClickLabelModifier.clickable lub Modifier.combinedClickable.

W przypadku złożonych interakcji, których nie można przypisać do standardowych kliknięć, użyj elementu customActions.

Jeśli na przykład aplikacja umożliwia użytkownikom przeciąganie elementu w inne miejsce lub przesuwanie palcem po elemencie na liście, możesz zapewnić alternatywny sposób wykonywania tych czynności, udostępniając działanie usługom ułatwień dostępu. Dzięki temu użytkownicy usług TalkBack, Voice Access lub Switch Access mogą wykonywać działania, które w inny sposób byłyby dostępne tylko za pomocą gestów.

W Compose możesz zdefiniować niestandardowe działania związane z ułatwieniami dostępu za pomocą właściwości customActions w modyfikatorze semantics, używając CustomAccessibilityAction.

Jeśli na przykład aplikacja umożliwia użytkownikom odrzucanie elementu przez przesunięcie, możesz udostępnić tę funkcję za pomocą niestandardowego działania ułatwień dostępu:

SwipeToDismissBox(
    modifier = Modifier.semantics {
        // Represents the swipe to dismiss for accessibility
        customActions = listOf(
            CustomAccessibilityAction(
                label = "Remove article from list",
                action = {
                    removeArticle()
                    true
                }
            )
        )
    },
    state = rememberSwipeToDismissBoxState(),
    backgroundContent = {}
) {
    ArticleListItem()
}

Po wdrożeniu niestandardowego działania ułatwień dostępu użytkownicy mogą uzyskać dostęp do działania w menu działań.

Więcej informacji o działaniach niestandardowych znajdziesz w artykule Działania niestandardowe.

Zapewnienie zrozumiałości dostępnych działań

Gdy element interfejsu obsługuje działania takie jak naciśnięcie i przytrzymanie, usługa ułatwień dostępu, np. TalkBack, informuje o tym, mówiąc „Kliknij dwukrotnie i przytrzymaj, aby wykonać długie naciśnięcie”.

Ten ogólny komunikat nie daje użytkownikowi żadnego kontekstu dotyczącego działania „naciśnij i przytrzymaj”.

Aby to ogłoszenie było bardziej przydatne, podaj opis działania.

W Compose standardowe modyfikatory interakcji, takie jak clickablecombinedClickable, mają wbudowane parametry (czyli onClickLabelonLongClickLabel), których możesz używać do podawania opisów działań, jak w tym przykładzie:

var contextMenuPhotoId by rememberSaveable { mutableStateOf<Int?>(null) }
val haptics = LocalHapticFeedback.current
LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) {
    items(photos, { it.id }) { photo ->
        ImageItem(
            photo,
            Modifier
                .combinedClickable(
                    onClick = { activePhotoId = photo.id },
                    onLongClick = {
                        haptics.performHapticFeedback(HapticFeedbackType.LongPress)
                        contextMenuPhotoId = photo.id
                    },
                    onLongClickLabel = stringResource(R.string.open_context_menu)
                )
        )
    }
}
if (contextMenuPhotoId != null) {
    PhotoActionsSheet(
        photo = photos.first { it.id == contextMenuPhotoId },
        onDismissSheet = { contextMenuPhotoId = null }
    )
}

W rezultacie TalkBack odczyta „Otwórz menu kontekstowe”, co pomoże użytkownikom zrozumieć cel działania.

Etykietę możesz też podać bezpośrednio w modyfikatorze semantics.

Więcej informacji o reagowaniu na kliknięcia i naciśnięcia znajdziesz w sekcjach Naciśnięcie i kliknięcie oraz Elementy interaktywne.

Korzystanie z wbudowanych ułatwień dostępu

Podczas projektowania interfejsu aplikacji korzystaj z wbudowanych funkcji ułatwień dostępu, aby uniknąć ponownego wdrażania funkcji, które już istnieją. Interfejsy API Material, Compose UI i Foundation domyślnie implementują i oferują wiele praktyk związanych z ułatwieniami dostępu.

W Jetpack Compose używaj wbudowanych funkcji kompozycyjnych, takich jak Button, Switch i Checkbox, aby tworzyć interfejsy dostępne dla osób z niepełnosprawnościami. Te komponenty są dostarczane z wbudowanymi modyfikatorami, takimi jak rolestateDescription, których możesz używać, aby zwiększyć dostępność aplikacji.semantics

Stosowanie semantyki w komponentach niestandardowych

Podczas tworzenia komponentu niestandardowego pamiętaj, jakiego rodzaju ułatwienia dostępu wymaga ten komponent, aby spełniać swoją rolę. Często wystarczą standardowe interfejsy API Compose, których już używasz, np. clickable, toggleable lub selectable, ponieważ automatycznie wypełniają one drzewo semantyczne.

Niektóre komponenty wymagają jednak bardziej szczegółowych informacji niż standardowe modyfikatory. W takich przypadkach poszukaj specjalistycznych modyfikatorów (np. triStateToggleable) lub, jeśli ich nie ma, podaj semantykę wprost za pomocą modyfikatora niskiego poziomu Modifier.semantics.

Załóżmy, że masz TriStateSwitch, czyli przełącznik z 3 stanami (włączony, wyłączony i nieokreślony).

Standardowy modyfikator toggleable zakłada 2 stany, a modyfikator triStateToggleable obsługuje złożoność trzeciego stanu. Automatycznie ustawia dostępność Role (Switch) i State. Dzięki temu usługi ułatwień dostępu otrzymują dokładne informacje i nie musisz ręcznie definiować semantyki.

Poniższy fragment kodu pokazuje TriStateSwitch z użyciem tej metody:

@Composable
fun TriStateSwitch(
    state: ToggleableState,
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    // A real implementation would include custom drawing for the switch.
    // This example uses a Box to demonstrate the semantics.
    Box(
        modifier = modifier
            .size(width = 64.dp, height = 40.dp)
            // triStateToggleable handles the semantics (Role and State)
            // automatically, so explicit Modifier.semantics is not needed here.
            .triStateToggleable(
                state = state,
                onClick = onClick,
                role = Role.Switch
            )
            // Add visual feedback based on the state
            .background(
                when (state) {
                    ToggleableState.On -> Color.Green
                    ToggleableState.Off -> Color.Gray
                    ToggleableState.Indeterminate -> Color.Yellow
                }
            )
    )
}

// Usage within another composable:
var state by remember { mutableStateOf(ToggleableState.Off) }
TriStateSwitch(
    state = state,
    onClick = {
        state = when (state) {
            ToggleableState.Off -> ToggleableState.Indeterminate
            ToggleableState.Indeterminate -> ToggleableState.On
            ToggleableState.On -> ToggleableState.Off
        }
    }
)

Podczas tworzenia komponentu niestandardowego zadbaj o to, aby podać wszystkie odpowiednie właściwości semantyczne, które ułatwią korzystanie z aplikacji osobom z niepełnosprawnościami. Jeśli na przykład komponent naśladuje standardowy element sterujący, taki jak przełącznik lub przycisk, te właściwości obejmują rolę komponentu (np. Role.Switch lub Role.Button), stateDescription (np. „Włączony”, „Wyłączony”, „Zaznaczony” lub „Niezaznaczony”) oraz odpowiednie etykiety działań. Więcej informacji znajdziesz w artykule Komponenty niestandardowe.

Używaj wskazówek innych niż kolor

Aby ułatwić korzystanie z aplikacji użytkownikom z zaburzeniami rozpoznawania barw, używaj na ekranach aplikacji innych wskazówek niż kolor. Mogą one obejmować używanie różnych kształtów lub rozmiarów, podawanie wzorców tekstowych lub wizualnych albo dodawanie informacji zwrotnych opartych na dźwięku lub dotyku (haptycznych) w celu zaznaczenia różnic między elementami.

Ilustracja 1 przedstawia 2 wersje aktywności. W jednej wersji do rozróżniania 2 możliwych działań w przepływie pracy używany jest tylko kolor. Druga wersja wykorzystuje sprawdzoną metodę, która polega na dodaniu kształtów i tekstu do koloru, aby podkreślić różnice między tymi 2 opcjami:

Po lewej stronie znajduje się ekran z 2 okrągłymi przyciskami: zielonym i czerwonym. Po prawej stronie znajduje się ten sam ekran, ale 2 okrągłe przyciski są oznaczone tekstem i znaczącymi ikonami.
Rysunek 1. Przykłady tworzenia elementów interfejsu za pomocą samego koloru (po lewej) oraz za pomocą koloru, kształtów i tekstu (po prawej).

Ułatwianie dostępu do treści multimedialnych

Jeśli tworzysz aplikację, która zawiera treści multimedialne, takie jak klip wideo lub nagranie dźwiękowe, zadbaj o to, aby użytkownicy o różnych potrzebach w zakresie ułatwień dostępu mogli zrozumieć materiał. W szczególności spróbuj wykonać te czynności:

  • zawierać elementy sterujące, które umożliwiają użytkownikom wstrzymywanie lub zatrzymywanie multimediów, zmianę głośności i włączanie/wyłączanie napisów;
  • Jeśli film zawiera informacje niezbędne do ukończenia procesu, udostępnij te same treści w alternatywnym formacie, np. w transkrypcji.

Dodatkowe materiały

Więcej informacji o zwiększaniu dostępności aplikacji znajdziesz w tych materiałach:

Codelabs

Wyświetlanie treści