API Material, Compose UI и Foundation реализуют и предлагают множество доступных практик по умолчанию. Они содержат встроенную семантику, соответствующую их конкретной роли и функции. Это означает, что поддержка доступности в большинстве случаев обеспечивается практически без дополнительных усилий.
Использование соответствующих API для соответствующих целей означает, что компоненты обычно поставляются с предопределёнными характеристиками доступности, охватывающими стандартные сценарии использования. Однако всегда проверяйте, соответствуют ли эти значения по умолчанию вашим потребностям в доступности. Если нет, Compose предлагает способы удовлетворения более специфических требований.
Понимание семантики и шаблонов доступности по умолчанию в API Compose поможет вам использовать их с учётом доступности. Это также поможет вам поддерживать доступность в более пользовательских компонентах.
Минимальные размеры сенсорной области
Любой элемент на экране, на который можно нажать, коснуться или с которым можно взаимодействовать, должен быть достаточно большим для обеспечения надёжного взаимодействия. При определении размера этих элементов обязательно установите минимальный размер 48 dp, чтобы обеспечить соответствие рекомендациям Material Design по доступности .
Компоненты Material, такие как Checkbox , RadioButton , Switch , Slider и Surface устанавливают этот минимальный размер внутренне, но только в том случае, если компонент может принимать действия пользователя. Например, если параметр onCheckedChange Checkbox имеет ненулевое значение, флажок включает отступы, чтобы иметь ширину и высоту не менее 48 dp.
@Composable private fun CheckableCheckbox() { Checkbox(checked = true, onCheckedChange = {}) }

Если параметр onCheckedChange имеет значение null, заполнение не включается, поскольку с компонентом невозможно взаимодействовать напрямую.
@Composable private fun NonClickableCheckbox() { Checkbox(checked = true, onCheckedChange = null) }

При реализации элементов управления выбором, таких как Switch , RadioButton или Checkbox , вы обычно переносите поведение нажатия на родительский контейнер, устанавливая обратный вызов click для компонуемого объекта на null и добавляя toggleable или selectable модификатор к родительскому компонуемому объекту.
@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) } } }

Если размер кликабельного компонуемого элемента меньше минимального размера сенсорной области, Compose всё равно увеличивает размер сенсорной области, расширяя её за пределы компонуемого элемента.
В следующем примере показан очень маленький интерактивный элемент Box . Область касания автоматически расширяется за пределы Box , поэтому нажатие рядом с Box по-прежнему вызывает событие щелчка.
@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) ) } }

Чтобы предотвратить возможное перекрытие сенсорных областей разных компонуемых элементов, всегда используйте достаточно большой минимальный размер для компонуемого элемента. В данном примере это означало бы использование модификатора sizeIn для установки минимального размера внутреннего блока:
@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) ) } }

Графические элементы
При определении компонуемого Image или Icon фреймворк Android не может автоматически определить, что именно отображает приложение. Вам необходимо передать текстовое описание графического элемента.
Представьте себе экран, на котором пользователь может поделиться текущей страницей с друзьями. На этом экране есть кликабельный значок «Поделиться»:

Фреймворк Android не может описать значок пользователю с нарушением зрения, основываясь только на нём. Для этого требуется дополнительное текстовое описание значка.
Параметр contentDescription описывает графический элемент. Используйте локализованную строку, так как она видна пользователю.
@Composable private fun ShareButton(onClick: () -> Unit) { IconButton(onClick = onClick) { Icon( imageVector = Icons.Filled.Share, contentDescription = stringResource(R.string.label_share) ) } }
Некоторые графические элементы носят исключительно декоративный характер, и вы можете не захотеть сообщать о них пользователю. Устанавливая параметр contentDescription в null , вы сообщаете фреймворку Android, что у этого элемента нет связанных действий или состояний.
@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) ) }
contentDescription в основном предназначен для графических элементов, таких как изображения. Материальные компоненты, такие как Button или Text , а также интерактивные элементы, такие как clickable или toggleable , имеют другие предопределённые семантики, описывающие их внутреннее поведение, и могут быть изменены через другие API Compose.
Интерактивные элементы
API Material и Foundation Compose создают элементы пользовательского интерфейса, с которыми пользователи могут взаимодействовать через API-модификаторы clickable и toggleable . Поскольку интерактивные компоненты могут состоять из нескольких элементов, clickable и toggleable по умолчанию объединяют семантику своих дочерних компонентов, так что компонент рассматривается как единое логическое целое.
Например, Button может состоять из значка дочернего элемента и текста. Вместо того, чтобы рассматривать дочерние элементы как отдельные элементы, Button по умолчанию объединяет семантику своих дочерних элементов, чтобы службы доступности могли группировать их соответствующим образом:

Аналогичным образом, использование модификатора clickable также приводит к тому, что компонуемый элемент объединяет семантику своих потомков в единую сущность, которая отправляется службам доступности с соответствующим представлением действия:
Row( // Uses `mergeDescendants = true` under the hood modifier = Modifier.clickable { openArticle() } ) { Icon( painter = painterResource(R.drawable.ic_logo), contentDescription = "Open", ) Text("Accessibility in Compose") }
Вы также можете задать специальный параметр onClickLabel для родительского кликабельного элемента, чтобы предоставить службам специальных возможностей дополнительную информацию и предложить более точное представление действия:
Row( modifier = Modifier .clickable(onClickLabel = "Open this article") { openArticle() } ) { Icon( painter = painterResource(R.drawable.ic_logo), contentDescription = "Open" ) Text("Accessibility in Compose") }
Если использовать TalkBack в качестве примера, этот clickable модификатор и его метка нажатия позволят TalkBack выдавать подсказку о действии «Коснитесь дважды, чтобы открыть эту статью», а не более общую обратную связь по умолчанию «Коснитесь дважды, чтобы активировать».
Эта обратная связь меняется в зависимости от типа действия. Длительное нажатие выводит подсказку TalkBack: «Дважды нажмите и удерживайте, чтобы», а затем — подпись:
Row( modifier = Modifier .combinedClickable( onLongClickLabel = "Bookmark this article", onLongClick = { addToBookmarks() }, onClickLabel = "Open this article", onClick = { openArticle() }, ) ) {}
В некоторых случаях у вас может не быть прямого доступа к модификатору clickable (например, если он установлен где-то на нижнем вложенном слое), но вы всё равно хотите изменить метку объявления по умолчанию. Для этого разделите установку clickable от изменения объявления с помощью модификатора semantics и установите метку click там же, чтобы изменить представление действия:
@Composable private fun ArticleList(openArticle: () -> Unit) { NestedArticleListItem( // Clickable is set separately, in a nested layer: onClickAction = openArticle, // Semantics are set here: modifier = Modifier.semantics { onClick( label = "Open this article", action = { // Not needed here: openArticle() true } ) } ) }
Вам не нужно передавать действие click дважды. Существующие API Compose, такие как clickable или Button , делают это автоматически. Логика слияния проверяет, что метка и действие самого внешнего модификатора (label) и действие (action) применяются к имеющейся информации. В предыдущем примере NestedArticleListItem автоматически передаёт действие click openArticle() своей семантике clickable . Вы можете оставить действие click null во втором модификаторе семантики action. Однако метка click берётся из второго модификатора семантики onClick(label = "Open this document") поскольку в первом она отсутствовала.
Вы можете столкнуться со сценариями, в которых вы ожидаете объединения семантики дочерних элементов с семантикой родительских элементов, но этого не происходит. Подробнее см. в разделе «Объединение и очистка» .
Пользовательские компоненты
При создании собственного компонента изучите реализацию аналогичного компонента в библиотеке Material или других библиотеках Compose. Затем при необходимости скопируйте или измените его поведение в плане доступности. Например, если вы замените флажок Material Checkbox собственной реализацией, просмотр существующей реализации Checkbox напомнит вам о необходимости добавить модификатор triStateToggleable , который управляет свойствами доступности компонента. Кроме того, активно используйте модификаторы Foundation, поскольку они учитывают встроенные аспекты доступности и существующие практики Compose, описанные в этом разделе.
Пример пользовательского компонента-переключателя можно также найти в разделе Очистка и установка семантики , а более подробную информацию о том, как обеспечить поддержку доступности в пользовательских компонентах, можно найти в руководстве по API .
{% дословно %}Рекомендовано для вас
- Примечание: текст ссылки отображается, когда JavaScript отключен.
- Доступность в Compose
- Тестирование макета Compose