Para ajudar pessoas com necessidades de acessibilidade a usar seu app, projete seu app para atender aos principais requisitos de acessibilidade.
Considerar os tamanhos mínimos de área de toque
Todos os elementos mostrados na tela que possam ser clicados, tocados ou com os quais é possível interagir de alguma outra forma precisam ser grandes o suficiente para uma interação confiável. Ao dimensionar esses elementos, certifique-se de defina o tamanho mínimo como 48 dp para seguir corretamente a especificação do Material Design diretrizes de acessibilidade.
componentes do Material Design, como Checkbox
, RadioButton
e Switch
.
Slider
e Surface
: definem esse tamanho mínimo internamente, mas apenas
quando o componente pode receber ações do usuário. Por exemplo, quando um Checkbox
tem
seu parâmetro onCheckedChange
definido com um valor não nulo, a caixa de seleção inclui
o padding tenha uma altura e largura de pelo menos 48 dp.
@Composable private fun CheckableCheckbox() { Checkbox(checked = true, onCheckedChange = {}) }
Quando o parâmetro onCheckedChange
é definido como nulo, o padding não é
incluído, porque não é possível interagir diretamente com o componente.
@Composable private fun NonClickableCheckbox() { Checkbox(checked = true, onCheckedChange = null) }
Ao implementar controles de seleção, como Switch
, RadioButton
ou
Checkbox
, você normalmente aumenta o comportamento clicável para um contêiner pai, define
o callback de clique no elemento combinável para null
e adicione um toggleable
ou
selectable
ao elemento combinável pai.
@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) } } }
Quando o tamanho de um elemento clicável é menor que o tamanho mínimo da área de toque, o Compose aumenta o tamanho dessa área. Ele faz isso expandindo tamanho da área de toque fora dos limites do elemento combinável
O exemplo a seguir contém um Box
clicável muito pequeno. Área de toque
é automaticamente expandida para além dos limites do Box
. Portanto, tocar
ao lado de Box
ainda aciona o evento de clique.
@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) ) } }
Para evitar possíveis sobreposições entre as áreas de toque de diferentes elementos combináveis, sempre
use um tamanho mínimo grande o suficiente para o elemento combinável. No exemplo, isso seria
significa usar o modificador sizeIn
para definir o tamanho mínimo para a caixa interna:
@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) ) } }
Adicionar etiquetas de clique
Você pode usar uma etiqueta de clique para adicionar um significado semântico ao comportamento de clique de uma função que pode ser composta. Os marcadores de clique descrevem o que acontece quando o usuário interage com o combinável. Os serviços de acessibilidade usam rótulos de clique para ajudar a descrever o app para usuários com necessidades específicas.
Defina a etiqueta de clique transmitindo um parâmetro no modificador 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 ) ) { // .. } }
Como alternativa, se você não tiver acesso ao modificador clicável, defina Clique na etiqueta no modificador semantics:
@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) } ) { // .. } }
Descrever elementos visuais
Quando você define um elemento combinável Image
ou Icon
, não há
maneira automática para o framework do Android entender o que é o app
exibidos. Você precisa transmitir uma descrição textual do elemento visual.
Imagine uma tela em que o usuário pode compartilhar a página atual com amigos. Essa tela contém um ícone de compartilhamento clicável:
Com base apenas no ícone, o framework do Android não pode descrevê-lo para uma com deficiência. O framework do Android precisa de uma descrição textual adicional do no ícone.
O parâmetro contentDescription
descreve um elemento visual. Usar um tipo
já que ela é visível para o usuário.
@Composable private fun ShareButton(onClick: () -> Unit) { IconButton(onClick = onClick) { Icon( imageVector = Icons.Filled.Share, contentDescription = stringResource(R.string.label_share) ) } }
Alguns elementos visuais são meramente decorativos e você pode não querer comunicar
ao usuário. Ao definir o parâmetro contentDescription
como null
, você
indicar ao framework do Android que esse elemento não foi associado
ações ou estados.
@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) ) }
Cabe a você decidir se um determinado elemento visual precisa de uma
contentDescription
. Pergunte a si mesmo se o elemento transmite informações que
que o usuário vai precisar
para realizar a tarefa. Caso contrário, é melhor deixar
descrição.
Mesclar elementos
Os serviços de acessibilidade, como o TalkBack e o acesso com interruptor, permitem que os usuários coloquem o foco em diferentes elementos na tela. É importante que o foco nos elementos tenha a granularidade correta. Quando cada elemento combinável de baixo nível na tela é e focados de forma independente, os usuários têm que interagir muito para se mover pela tela. Se os elementos se mesclarem de forma muito agressiva, os usuários podem não entender quais elementos estão juntos
Quando você aplica um modificador clickable
a um elemento combinável, o Compose
mescla automaticamente todos os elementos que podem ser compostos. Isso também vale para
ListItem
elementos de um item de lista se mesclam, e a acessibilidade
serviços os veem como um elemento.
É possível definir um conjunto de funções que podem ser compostas que formem um grupo lógico, mas esse grupo não será clicável nem fará parte de um item de lista. Ainda é melhor ter acessibilidade serviços para vê-los como um elemento. Por exemplo, imagine um elemento combinável que mostra o avatar de um usuário, seu nome e algumas informações extras:
Você pode permitir que o Compose mescle esses elementos usando o mergeDescendants
.
no modificador semantics
. Dessa forma, os serviços de acessibilidade
seleciona apenas o elemento mesclado e todas as propriedades semânticas dos descendentes
são mesclados.
@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") } } }
Os serviços de acessibilidade agora se concentram em todo o contêiner de uma só vez, mesclando seus conteúdos:
Adicionar ações personalizadas
Veja o seguinte item de lista:
Quando você usa um leitor de tela, como o TalkBack, para ouvir o que é exibido no ele primeiro seleciona o item inteiro e, em seguida, o ícone de favorito.
Em uma lista longa, isso pode ficar muito repetitivo. Uma abordagem melhor é
definir uma ação personalizada que permita que um usuário adicione o item aos favoritos. Observação importante
que você também tem que remover explicitamente o comportamento do ícone de favorito
para garantir que não seja selecionado pelo serviço de acessibilidade. Isso
usa o modificador 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 { } ) } }
Descrever o estado de um elemento
Um elemento combinável pode definir uma stateDescription
como semântica que o
O framework do Android usa para ler o estado em que o elemento combinável se encontra. Para
por exemplo, um elemento combinável alternável pode estar em um ambiente ou "desmarcada"
estado. Em alguns casos, convém substituir a descrição de estado padrão
rótulos que o Compose usa. Para isso, especifique explicitamente o estado
rótulos de descrição antes de definir um elemento combinável como alternável:
@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() } ) ) { /* ... */ } }
Definir cabeçalhos
Às vezes, os apps mostram muito conteúdo em uma tela em um contêiner rolável. Por exemplo, uma tela pode mostrar todo o conteúdo de um artigo que o usuário está lendo:
Usuários com necessidades de acessibilidade têm dificuldade para navegar nessa tela. Para ajudar de navegação, indicam quais elementos são cabeçalhos. No exemplo anterior, cada o título da subseção pode ser definido como um cabeçalho para acessibilidade. Algumas serviços de acessibilidade, como o Talkback, permitem que os usuários naveguem diretamente de indo para o cabeçalho.
No Compose, para indicar que um elemento combinável é um cabeçalho, defina o
Propriedade semantics
:
@Composable private fun Subsection(text: String) { Text( text = text, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.semantics { heading() } ) }
Processar elementos combináveis personalizados
Sempre que você substituir determinados componentes do Material Design no seu app por é necessário considerar a acessibilidade.
Digamos que você esteja substituindo o Material Checkbox
pela sua própria implementação.
Você pode se esquecer de adicionar o modificador triStateToggleable
, que processa
as propriedades de acessibilidade desse componente.
Como regra geral, observe a implementação do componente em a biblioteca do Material Design e imitar qualquer comportamento de acessibilidade que você encontrar. Além disso, use os modificadores do Compose Foundation, e não modificadores no nível da IU, porque eles incluem considerações de acessibilidade prontas.
Testar a implementação do componente personalizado com vários serviços de acessibilidade para verificar o comportamento dele.
Outros recursos
- Acessibilidade:conceitos e conceitos essenciais técnicas comuns a todo o desenvolvimento de apps Android
- Criar apps acessíveis:etapas principais para deixar seu app mais acessível
- Princípios para melhorar o app acessibilidade:os princípios-chave para ter em mente ao trabalhar para tornar seu app mais acessível
- Testes de acessibilidade: Princípios e ferramentas de teste para acessibilidade no Android