В Material, Compose UI и Foundation API по умолчанию реализованы многие функции, обеспечивающие доступность. Они содержат встроенную семантику, соответствующую их роли и функции. Это означает, что большинство функций специальных возможностей предоставляются без дополнительных усилий.
Использование подходящих 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, обычно интерактивность переносится на родительский контейнер. Для этого в composable-функцию добавляется обратный вызов клика null, а в родительскую composable-функцию – модификатор 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) } } }
Если размер composable-функции, по которой можно кликнуть, меньше минимального размера области прикосновения, Compose все равно увеличивает область прикосновения. Это происходит за счет увеличения области прикосновения за пределами границ composable-функции.
В примере ниже показана очень маленькая кликабельная 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) ) } }
Чтобы избежать возможного перекрытия областей касания разных composable-функций, всегда используйте достаточно большой минимальный размер для composable-функции. В этом примере нужно использовать модификатор 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) ) } }
Графические элементы
Когда вы определяете composable-функцию Image или Icon, фреймворк Android не может автоматически понять, что именно отображает приложение. Вам нужно передать текстовое описание графического элемента.
Представьте экран, на котором пользователь может поделиться текущей страницей с друзьями. На этом экране есть значок "Поделиться", на который можно нажать:
Только по значку фреймворк 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 по умолчанию объединяют семантику дочерних элементов, чтобы компонент воспринимался как единый логический объект.
Например, элемент Material Button может состоять из дочернего значка и текста. Вместо того чтобы рассматривать дочерние элементы как отдельные объекты, Material
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 и задав ярлык клика, чтобы изменить представление действия:
@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 } ) } ) }
Не нужно передавать действие при клике дважды. Существующие API Compose, такие как clickable или Button, обрабатывают это за вас. Логика объединения проверяет, что для имеющейся информации используются внешняя метка модификатора и действие. В примере выше NestedArticleListItem автоматически передает действие нажатия openArticle() в семантику clickable. Во втором модификаторе семантики можно оставить действие при нажатии пустым. Однако ярлык клика берется из второго семантического модификатора onClick(label = "Open this document"), поскольку в первом его нет.
Иногда семантика дочернего элемента не объединяется с семантикой родительского элемента. Подробнее о слиянии и очистке…
Специальные компоненты
При создании собственного компонента изучите реализацию похожего компонента в библиотеке Material или других библиотеках Compose. Затем воспроизведите или измените его поведение в соответствии с требованиями специальных возможностей. Например, если вы замените Material Checkbox собственной реализацией, то, посмотрев на существующую реализацию Checkbox, вы вспомните, что нужно добавить модификатор triStateToggleable, который обрабатывает свойства доступности для компонента. Кроме того, активно используйте модификаторы Foundation, поскольку они включают встроенные функции доступности и существующие методы Compose, описанные в этом разделе.
Пример компонента переключателя можно найти в разделе о том, как задавать и очищать семантику. Более подробная информация о том, как обеспечить доступность специальных компонентов, приведена в руководстве по API.
Рекомендуем
- Примечание. Текст ссылки показывается, когда JavaScript отключен.
- Специальные возможности в Compose
- Как протестировать макет письма