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

Aby pomóc użytkownikom z potrzebami związanymi z ułatwieniami dostępu, platforma Android umożliwia utworzenie usługi ułatwień dostępu, która może prezentować użytkownikom treści z aplikacji, a także obsługiwać aplikacje w ich imieniu.

Android udostępnia kilka 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 ułatwić osobom z potrzebami związanymi z ułatwieniami dostępu korzystanie z Twojej aplikacji, musi ona być zgodna ze sprawdzonymi metodami opisanymi na tej stronie, które opierają się na wytycznych opisanych w artykule Zwiększanie dostępności aplikacji.

Każda z tych sprawdzonych metod, opisanych w kolejnych sekcjach, może dodatkowo poprawić działanie ułatwień dostępu w aplikacji:

Elementy etykiety
Użytkownicy muszą być w stanie zrozumieć treść i cel każdego interaktywnego i istotnego elementu interfejsu w aplikacji.
Dodawanie działań ułatwień dostępu
Dodając działania ułatwień dostępu, możesz umożliwić użytkownikom usług ułatwień dostępu wykonywanie kluczowych wzorców przeglądania w aplikacji.
Korzystanie z wbudowanych ułatwień dostępu
Compose domyślnie oferuje wiele funkcji ułatwień dostępu. Skorzystaj ze wstępnie zdefiniowanych zachowań ułatwień dostępu, aby zapewnić dostępność komponentów przy niewielkim nakładzie pracy lub bez dodatkowego wysiłku. 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żywanie innych wskazówek niż kolor
Użytkownicy muszą mieć możliwość wyraźnego rozróżnienia kategorii elementów w interfejsie. Aby to zrobić, użyj wzorów i pozycji, a także kolorów, aby wyrazić te różnice.
Zwiększanie dostępności treści multimedialnych
Dodaj opisy do treści wideo lub audio w aplikacji, aby użytkownicy, którzy z nich korzystają, nie musieli polegać wyłącznie na wskazówkach wizualnych lub dźwiękowych.

Elementy etykiety

Ważne jest, aby każdy interaktywny element interfejsu w aplikacji miał przydatną i opisową etykietę. Każda etykieta musi wyjaśniać semantykę danego elementu, czyli jego znaczenie i cel. Czytniki ekranu, takie jak TalkBack, mogą odczytywać te etykiety użytkownikom.

W większości przypadków interfejsy API Compose i Material mają domyślnie włączoną 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 artykule Semantyka.

W sekcjach poniżej opisano kilka innych technik oznaczania etykietami.

Elementy edytowalne

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

W tym przykładzie 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 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 wprowadzanych przez użytkownika znajdziesz w artykule Konfigurowanie pól tekstowych.

Liczba elementów w kolekcji

Podczas dodawania etykiet do elementów kolekcji każda etykieta musi być unikalna. Dzięki temu usługi ułatwień dostępu systemu mogą odwoływać się do dokładnie jednego elementu na ekranie podczas odczytywania etykiety. Dzięki temu użytkownicy wiedzą, kiedy przechodzą przez interfejs lub kiedy przenoszą zaznaczenie na element, który już odkryli.

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

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 listach 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 treś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.

We fragmencie kodu poniżej funkcja kompozycyjna Row działa jako kontener nadrzędny. W elemencie Row znajdują się powiązane elementy, które wyświetlają metadane posta na blogu – awatar autora, imię i nazwisko autora 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")
        }
    }
}

Podczas grupowania powiązanych elementów, jak w poprzednim przykładzie, ustaw jako interaktywny 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 jednej wypowiedzi, dlatego ważne jest, aby każdy opis był jak najkrótszy, ale jednocześnie przekazywał znaczenie elementu.

Uwaga: podczas tworzenia opisu treści dla grupy unikaj agregowania tekstu jej elementów podrzędnych. Może to spowodować, że opis grupy będzie niestabilny, 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 skonsolidować tekst podrzędnych węzłów tekstowych elementu listy lub siatki. Najlepiej nie modyfikować tego ogłoszenia.

Więcej informacji o semantyce scalania 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ść ułatwia poruszanie się po tekście.

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

Tytuły paneli ułatwień dostępu

W Androidzie 9 (poziom interfejsu API 28) i nowszych możesz podawać ułatwiające dostęp tytuły paneli ekranu. W kontekście ułatwień dostępu panel to wizualnie odrębna część okna.

Aby usługi ułatwień dostępu mogły zrozumieć zachowanie panelu przypominające okno, nadaj panelom aplikacji opisowe tytuły. Dzięki temu usługi ułatwień dostępu mogą 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 semantyki paneTitle znajdziesz w artykule o komponentach podobnych do okien.

Elementy dekoracyjne

Jeśli element w interfejsie użytkownika służy tylko do wizualnego odstępu lub wyglądu, ustaw odpowiednie właściwości elementu, aby wskazać, że usługi ułatwień dostępu mogą go ignorować.

W przypadku funkcji kompozycyjnych Image lub Icon ustaw contentDescription = null. W przypadku innych elementów czysto 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, że mają ignorować dany element.

Jeśli interaktywny element kompozycyjny zawiera dekoracyjne, nieinteraktywne elementy podrzędne, użyj clearAndSetSemantics, aby upewnić się, że usługi ułatwień dostępu nie będą ich przechodzić. Pamiętaj, że clearAndSetSemantics całkowicie usuwa domyślną semantykę elementu i jego elementów podrzędnych. Pozwala to zdefiniować nowy, ujednolicony element ułatwień dostępu. Zwykle stosuje się to podejście w przypadku złożonych komponentów niestandardowych.

W przykładzie poniżej Icon i Text to dekoracyjne elementy podrzędne 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ę, używając clearAndSetSemantics w elemencie nadrzędnym Row. Dzięki temu usługi ułatwień dostępu traktują cały element Row jako przełącznik, który można przechodzić:

// 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 wykonać wszystkie wzorce przeglądania w aplikacji.

Jeśli interakcja z niestandardowym elementem kompozycyjnym zmienia stan aplikacji w sposób, który nie jest oczywisty, podaj etykiety opisowe dla standardowych działań polegających na kliknięciu, używając parametrów takich jak onClickLabel lub onLongClickLabel w Modifier.clickable lub Modifier.combinedClickable.

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

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

W Compose możesz definiować niestandardowe działania ułatwień 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 przesunięcie elementu, aby go odrzucić, 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 zaimplementowaniu niestandardowego działania ułatwień dostępu użytkownicy mogą uzyskać do niego dostęp w menu czynności.

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, ogłasza to jako „Kliknij dwukrotnie i przytrzymaj, aby nacisnąć i przytrzymać”.

Ten ogólny komunikat nie daje użytkownikowi żadnego kontekstu dotyczącego działania naciśnięcia i przytrzymania.

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

W Compose standardowe modyfikatory interakcji, takie jak clickable i combinedClickable, mają wbudowane parametry (onClickLabel i onLongClickLabel), 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 }
    )
}

Dzięki temu TalkBack odczyta „Otwórz menu kontekstowe”, co pomoże użytkownikom zrozumieć cel działania.

Możesz też określić etykietę bezpośrednio w modyfikatorze semantics.

Więcej informacji o reagowaniu na kliknięcia znajdziesz w artykułach Klikanie i naciskanie 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ć dostępne interfejsy. Te komponenty są dostarczane z modyfikatorami semantics, takimi jak role i stateDescription, których możesz używać, aby zwiększyć dostępność aplikacji.

Stosowanie semantyki do komponentów niestandardowych

Podczas tworzenia komponentu niestandardowego zastanów się, jakiego rodzaju ułatwień dostępu wymaga on do spełnienia swojej roli. Często wystarczą standardowe interfejsy API Compose, których już używasz, takie jak clickable, toggleable czy selectable, ponieważ automatycznie wypełniają drzewo semantyki.

Jednak niektóre komponenty wymagają bardziej szczegółowych informacji niż te, które są podawane w standardowych modyfikatorach. W takich przypadkach poszukaj specjalistycznych modyfikatorów (takich jak triStateToggleable) lub, jeśli nie ma żadnych, wyraźnie podaj semantykę za pomocą niskopoziomowego modyfikatora 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, natomiast modyfikator triStateToggleable obsługuje złożoność trzeciego stanu. Automatycznie ustawia ułatwienia dostępu 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, który korzysta z tego podejścia:

@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 pamiętaj o podaniu wszystkich odpowiednich właściwości semantycznych na potrzeby ułatwień dostępu. 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, do odróżniania elementów interfejsu na ekranach aplikacji używaj innych wskazówek niż kolor. Możesz na przykład użyć różnych kształtów lub rozmiarów, dodać tekst lub wzory wizualne albo dodać dźwięk lub reakcję haptyczną, aby zaznaczyć różnice między elementami.

Rysunek 1 przedstawia 2 wersje aktywności. W jednej wersji do rozróżnienia 2 możliwych działań w przepływie pracy użyto tylko koloru. Druga wersja wykorzystuje sprawdzoną metodę polegającą na użyciu kształtów i tekstu oprócz 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 ikonami o znaczeniu opisowym.
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).

Zwiększanie dostępności treści multimedialnych

Jeśli tworzysz aplikację, która zawiera treści multimedialne, takie jak klip wideo lub nagranie audio, postaraj się pomóc użytkownikom o różnych potrzebach związanych z ułatwieniami dostępu w zrozumieniu materiału. W szczególności spróbuj wykonać te czynności:

  • Uwzględnij elementy sterujące, które umożliwiają użytkownikom wstrzymywanie lub zatrzymywanie multimediów, zmianę głośności i włączanie napisów.
  • Jeśli film zawiera informacje, które są niezbędne do wykonania zadania, udostępnij te same treści w innym formacie, np. w formie transkrypcji.

Dodatkowe materiały

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

Codelabs

Wyświetlanie treści