Najważniejsze czynności dotyczące ułatwień dostępu do tworzenia wiadomości

Aby ułatwić osobom z niepełnosprawnościami korzystanie z Twojej aplikacji, zaprojektuj do obsługi najważniejszych ułatwień dostępu.

Weź pod uwagę minimalne rozmiary docelowych elementów dotykowych

Każdy element na ekranie, który można kliknąć, dotknąć lub w inny sposób aktywować, wystarczająco dużych, by zapewnić niezawodną interakcję. Podczas dobierania rozmiaru tych elementów pamiętaj, Ustaw minimalny rozmiar na 48 dp, by zachować zgodność z Material Design ze wskazówkami dotyczącymi ułatwień dostępu.

Komponenty materiałowe – takie jak Checkbox, RadioButton, Switch, Slider i Surface – ustaw ten minimalny rozmiar wewnętrznie, ale tylko gdy komponent może odbierać działania użytkownika. Jeśli na przykład Checkbox ma jego parametr onCheckedChange ma wartość inną niż null, pole wyboru zawiera dopełnienie musi mieć szerokość i wysokość co najmniej 48 dp.

@Composable
private fun CheckableCheckbox() {
    Checkbox(checked = true, onCheckedChange = {})
}

Jeśli parametr onCheckedChange ma wartość null, dopełnienie nie jest stosowane. uwzględnionych, ponieważ z komponentem nie można korzystać bezpośrednio.

@Composable
private fun NonClickableCheckbox() {
    Checkbox(checked = true, onCheckedChange = null)
}

Rysunek 1. Pole wyboru bez dopełnienia.

Implementując ustawienia wyboru, takie jak Switch, RadioButton lub Checkbox, zazwyczaj zwiększa się ruch klikalny na kontener nadrzędny wywołanie zwrotne kliknięcia dla funkcji null i dodaj do funkcji toggleable lub Modyfikator selectable do nadrzędnej funkcji kompozycyjnej.

@Composable
private fun CheckableRow() {
    MaterialTheme {
        var checked by remember { mutableStateOf(false) }
        Row(
            Modifier
                .toggleable(
                    value = checked,
                    role = Role.Checkbox,
                    onValueChange = { checked = !checked }
                )
                .padding(16.dp)
                .fillMaxWidth()
        ) {
            Text("Option", Modifier.weight(1f))
            Checkbox(checked = checked, onCheckedChange = null)
        }
    }
}

Gdy rozmiar klikalnego elementu kompozycyjnego jest mniejszy niż minimalny docelowy element dotykowy nadal zwiększa rozmiar docelowego elementu dotykowego. Robi to, rozwijając rozmiar docelowego elementu dotykowego wykracza poza granice funkcji kompozycyjnej.

Poniższy przykład zawiera bardzo mały klikalny Box. Docelowy element dotykowy obszar jest automatycznie rozszerzany poza granice obszaru Box, więc obok Box nadal wywołuje zdarzenie kliknięcia.

@Composable
private fun SmallBox() {
    var clicked by remember { mutableStateOf(false) }
    Box(
        Modifier
            .size(100.dp)
            .background(if (clicked) Color.DarkGray else Color.LightGray)
    ) {
        Box(
            Modifier
                .align(Alignment.Center)
                .clickable { clicked = !clicked }
                .background(Color.Black)
                .size(1.dp)
        )
    }
}

Aby uniknąć nakładania się obszarów dotykowych różnych elementów kompozycyjnych, zawsze używaj wystarczająco dużego minimalnego rozmiaru elementu kompozycyjnego. W tym przykładzie średnia z modyfikatorem sizeIn do ustawienia minimalnego rozmiaru wewnętrznego pola:

@Composable
private fun LargeBox() {
    var clicked by remember { mutableStateOf(false) }
    Box(
        Modifier
            .size(100.dp)
            .background(if (clicked) Color.DarkGray else Color.LightGray)
    ) {
        Box(
            Modifier
                .align(Alignment.Center)
                .clickable { clicked = !clicked }
                .background(Color.Black)
                .sizeIn(minWidth = 48.dp, minHeight = 48.dp)
        )
    }
}

Dodaj etykiety kliknięć

Etykieta kliknięcia pozwala nadać znaczenie semantycznemu działaniu polegającemu na kliknięciu kompozycyjne. Etykiety kliknięć informują, co się dzieje, gdy użytkownik wchodzi w interakcję z tagiem kompozycyjne. Usługi ułatwień dostępu korzystają z etykiet kliknięć, aby opisać aplikację użytkowników o określonych potrzebach.

Aby ustawić etykietę kliknięcia, przekaż parametr w modyfikatorze clickable:

@Composable
private fun ArticleListItem(openArticle: () -> Unit) {
    Row(
        Modifier.clickable(
            // R.string.action_read_article = "read article"
            onClickLabel = stringResource(R.string.action_read_article),
            onClick = openArticle
        )
    ) {
        // ..
    }
}

Jeśli nie masz dostępu do klikalnego modyfikatora, etykietę kliknięcia w modyfikatorze semantyki:

@Composable
private fun LowLevelClickLabel(openArticle: () -> Boolean) {
    // R.string.action_read_article = "read article"
    val readArticleLabel = stringResource(R.string.action_read_article)
    Canvas(
        Modifier.semantics {
            onClick(label = readArticleLabel, action = openArticle)
        }
    ) {
        // ..
    }
}

Opisz elementy wizualne

Gdy zdefiniujesz kompozycję Image lub Icon, nie będzie automatyczny sposób określania przez platformę Androida, czym jest aplikacja które są wyświetlane. Musisz przekazać opis tekstowy elementu wizualnego.

Wyobraź sobie ekran, na którym użytkownik może udostępnić bieżącą stronę znajomym. Ten Na ekranie znajduje się ikona udostępniania, którą można kliknąć:

Pasek ikon, które można kliknąć, oraz

Sama ikona nie jest w stanie opisać tego działania za pomocą platformy Androida. niepełnosprawnego użytkownika. Platforma Androida wymaga dodatkowego opisu ikonę.

Parametr contentDescription opisuje element wizualny. Użyj ciągu znaków, ponieważ są one widoczne dla użytkownika.

@Composable
private fun ShareButton(onClick: () -> Unit) {
    IconButton(onClick = onClick) {
        Icon(
            imageVector = Icons.Filled.Share,
            contentDescription = stringResource(R.string.label_share)
        )
    }
}

Niektóre elementy wizualne mają charakter czysto dekoracyjny i nie chcesz się z nimi komunikować i jak ich używać. Ustawienie parametru contentDescription na null wskazać platformie Androida, że ten element nie ma powiązanego działania lub stanu.

@Composable
private fun PostImage(post: Post, modifier: Modifier = Modifier) {
    val image = post.imageThumb ?: painterResource(R.drawable.placeholder_1_1)

    Image(
        painter = image,
        // Specify that this image has no semantic meaning
        contentDescription = null,
        modifier = modifier
            .size(40.dp, 40.dp)
            .clip(MaterialTheme.shapes.small)
    )
}

To Ty decydujesz, czy dany element wizualny wymaga contentDescription Zastanów się, czy element przekazuje informacje, do wykonania zadania. Jeśli nie, lepiej zostawić opis.

Scalanie elementów

Usługi ułatwień dostępu takie jak Talkback i Switch Access umożliwiają użytkownikom skupienie się między elementami na ekranie. Ważne jest, aby elementy skupiały się na z odpowiedniej szczegółowości. Gdy każda funkcja kompozycyjna niskiego poziomu na ekranie jest niezależnie od siebie, użytkownicy muszą wykonywać wiele działań, aby poruszać się po ekranie. Jeśli elementy połączą się zbyt intensywnie, użytkownicy mogą nie zrozumieć, elementy należą do siebie

Gdy zastosujesz modyfikator clickable do funkcji kompozycyjnej, funkcja Utwórz automatycznie łączy wszystkie elementy funkcji kompozycyjnej. Dotyczy to również ListItem; scalane elementy listy, ułatwienia dostępu usługi postrzegają je jako jeden element.

Można mieć zestaw elementów kompozycyjnych, które tworzą grupę logiczną, ale grupy nie można kliknąć ani być częścią elementu listy. Nadal przyda Ci się ułatwienia dostępu i traktować je jako jeden element. Wyobraź sobie na przykład utwór kompozycyjny, wyświetla awatar użytkownika, jego nazwę oraz dodatkowe informacje:

Grupa elementów interfejsu z nazwą użytkownika. Nazwa jest wybrana.

Możesz włączyć opcję Utwórz, aby scalić te elementy, za pomocą przycisku mergeDescendants w modyfikatorze semantics. W ten sposób usługi ułatwień dostępu zaznacz tylko scalony element i wszystkie właściwości semantyczne elementów podrzędnych zostaną scalone.

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

Usługi ułatwień dostępu skupiają się teraz na całym kontenerze naraz, scalając ich treści:

Grupa elementów interfejsu z nazwą użytkownika. Wszystkie elementy są zaznaczone razem.

Dodaj działania niestandardowe

Przyjrzyj się temu elementowi listy:

Typowy element listy zawierający tytuł artykułu, autora i ikonę zakładki.

Gdy używasz czytnika ekranu, takiego jak TalkBack, aby usłyszeć, co jest wyświetlane na najpierw cały element, a potem ikonę zakładki.

Element listy z zaznaczonymi wszystkimi elementami razem.

Pozycja na liście z zaznaczoną ikoną zakładki

W przypadku długiej listy może się to bardzo powtarzać. Lepszym sposobem jest zdefiniować działanie niestandardowe, które pozwala użytkownikowi dodać element do zakładek. Pamiętaj musisz też wyraźnie usunąć działanie ikony zakładki aby mieć pewność, że nie zostanie wybrana przez usługę ułatwień dostępu. Ten można użyć modyfikatora clearAndSetSemantics:

@Composable
private fun PostCardSimple(
    /* ... */
    isFavorite: Boolean,
    onToggleFavorite: () -> Boolean
) {
    val actionLabel = stringResource(
        if (isFavorite) R.string.unfavorite else R.string.favorite
    )
    Row(
        modifier = Modifier
            .clickable(onClick = { /* ... */ })
            .semantics {
                // Set any explicit semantic properties
                customActions = listOf(
                    CustomAccessibilityAction(actionLabel, onToggleFavorite)
                )
            }
    ) {
        /* ... */
        BookmarkButton(
            isBookmarked = isFavorite,
            onClick = onToggleFavorite,
            // Clear any semantics properties set on this node
            modifier = Modifier.clearAndSetSemantics { }
        )
    }
}

Opisz stan elementu

Funkcja kompozycyjna może zdefiniować element stateDescription semantyczny, którego Platforma Androida używa do odczytywania stanu, w jakim znajduje się funkcja kompozycyjna. Dla: na przykład włączana funkcja kompozycyjna może znajdować się lub „niezaznaczone” stanu. W niektórych przypadkach możesz chcieć zastąpić domyślny opis stanu używanych przez funkcję tworzenia wiadomości. Aby to zrobić, jawnie określ stan etykiet opisu przed zdefiniowaniem funkcji kompozycyjnej jako przełączania:

@Composable
private fun TopicItem(itemTitle: String, selected: Boolean, onToggle: () -> Unit) {
    val stateSubscribed = stringResource(R.string.subscribed)
    val stateNotSubscribed = stringResource(R.string.not_subscribed)
    Row(
        modifier = Modifier
            .semantics {
                // Set any explicit semantic properties
                stateDescription = if (selected) stateSubscribed else stateNotSubscribed
            }
            .toggleable(
                value = selected,
                onValueChange = { onToggle() }
            )
    ) {
        /* ... */
    }
}

Zdefiniuj nagłówki

Aplikacje czasami wyświetlają wiele treści na jednym ekranie w kontenerze z możliwością przewijania. Ekran może np. zawierać pełną treść artykułu, który użytkownik czyta:

Zrzut ekranu z postem na blogu z tekstem artykułu w kontenerze, który można przewijać.

Użytkownicy z niepełnosprawnościami mają problemy z poruszaniem się po takim ekranie. Do pomocy nawigacji, wskaż, które elementy są nagłówkami. W poprzednim przykładzie każda z tych wartości tytuł podsekcji można zdefiniować jako nagłówek dotyczący ułatwień dostępu. Niektóre usługi ułatwień dostępu, takie jak Talkback, pozwalają użytkownikom do nagłówka.

W narzędziu Compose wskazujesz, że funkcja kompozycyjna jest nagłówkiem, definiując Usługa semantics:

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

Obsługa niestandardowych elementów kompozycyjnych

Za każdym razem, gdy zmienisz w aplikacji określone komponenty Material Design na niestandardowe należy pamiętać o ułatwieniach dostępu.

Załóżmy, że zastępujesz Material Checkbox własną implementacją. Możesz zapomnieć o dodaniu modyfikatora triStateToggleable, który blokuje właściwości ułatwień dostępu tego komponentu.

Jako zasadę należy wziąć pod uwagę implementację komponentu w w bibliotece Material Design, i naśladują wszelkie dostępne funkcje. Dodatkowo, zamiast na poziomie interfejsu, używaj modyfikatorów fundamentów. modyfikatory, które domyślnie uwzględniają kwestie ułatwień dostępu.

Testowanie implementacji komponentu niestandardowego za pomocą wielu usług ułatwień dostępu, aby sprawdzić ich działanie.

Dodatkowe materiały