As APIs Material, Compose UI e Foundation implementam e oferecem muitas práticas acessíveis por padrão. Elas contêm semântica integrada que segue a função e o papel específicos. Isso significa que a maior parte do suporte à acessibilidade é fornecida com pouco ou nenhum trabalho extra.
Usar as APIs adequadas para a finalidade certa significa que os componentes geralmente vêm com comportamentos de acessibilidade predefinidos que abrangem casos de uso padrão. No entanto, sempre verifique se esses padrões atendem às suas necessidades de acessibilidade. Caso contrário, o Compose oferece maneiras de atender a requisitos mais específicos.
Entender a semântica e os padrões de acessibilidade padrão nas APIs do Compose ajuda você a usá-los com foco na acessibilidade. Ela também ajuda você a oferecer suporte à acessibilidade em componentes mais personalizados.
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, defina o tamanho mínimo como 48 dp para seguir corretamente as Diretrizes de acessibilidade do Material Design (link em inglês).
Os componentes do Material Design (como Checkbox, RadioButton, 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
o parâmetro onCheckedChange definido como um valor não nulo, a caixa de seleção inclui
padding com uma largura e uma altura 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 com o componente de forma direta.
@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
definindo o callback de clique no elemento combinável como null e adicionando um
modificador toggleable ou selectable ao elemento 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. Isso é feito expandindo o tamanho da área de toque para fora dos limites do elemento combinável.
O exemplo a seguir contém um elemento Box clicável muito pequeno. A área de toque
é expandida automaticamente para além dos limites do elemento Box. Então, tocar
ao lado de Box ainda acionará 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 áreas de toque de diferentes elementos combináveis, sempre
use um tamanho mínimo grande o suficiente. No exemplo, isso significa usar o modificador sizeIn para definir o tamanho mínimo da 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) ) } }
Elementos gráficos
Quando você define um elemento combinável Image ou Icon, não há
como o framework do Android entender de forma automática o que o app está
mostrando. É necessário fornecer uma descrição textual do elemento gráfico.
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:
Tendo somente o ícone como base, o framework do Android não consegue descrevê-lo para um usuário com deficiência visual. O framework do Android precisa de uma descrição textual complementar do ícone.
O parâmetro contentDescription descreve um elemento gráfico. Use uma string localizada, já que ela fica 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 gráficos são apenas decorativos, e você pode optar por não os descrever
ao usuário. Ao definir o parâmetro contentDescription
como null, você indica ao framework do Android que esse elemento não
tem ações ou estados associados.
@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) ) }
O contentDescription é usado principalmente para elementos gráficos, como imagens. Componentes do Material, como Button ou Text, e comportamentos acionáveis, como clickable ou toggleable, vêm com outras semânticas predefinidas que descrevem o comportamento intrínseco deles e podem ser mudadas por outras APIs do Compose.
Elementos interativos
As APIs Material e Foundation Compose criam elementos de UI com que os usuários podem interagir
usando as APIs de modificador clickable e toggleable. Como
componentes interativos podem consistir em vários elementos, clickable e
toggleable mesclam a semântica dos filhos por padrão para que o componente
seja tratado como uma entidade lógica.
Por exemplo, um Button do Material pode consistir em um ícone filho e algum texto. Em vez de tratar as crianças como indivíduos, um Button do Material mescla a semântica delas por padrão para que os serviços de acessibilidade possam agrupá-las de acordo com a necessidade:
Da mesma forma, usar o modificador clickable faz com que um elemento combinável
mescle a semântica dos descendentes em uma única entidade, que é enviada aos
serviços de acessibilidade com uma representação de ação correspondente:
Row( // Uses `mergeDescendants = true` under the hood modifier = Modifier.clickable { openArticle() } ) { Icon( painter = painterResource(R.drawable.ic_logo), contentDescription = "Open", ) Text("Accessibility in Compose") }
Você também pode definir um onClickLabel específico no elemento clicável principal para fornecer
mais informações aos serviços de acessibilidade e oferecer uma representação
mais refinada da ação:
Row( modifier = Modifier .clickable(onClickLabel = "Open this article") { openArticle() } ) { Icon( painter = painterResource(R.drawable.ic_logo), contentDescription = "Open" ) Text("Accessibility in Compose") }
Usando o TalkBack como exemplo, esse modificador clickable e o rótulo de clique
permitem que o TalkBack forneça uma dica de ação "Toque duas vezes para abrir este
artigo", em vez do feedback padrão mais genérico "Toque duas vezes para
ativar".
Esse feedback muda de acordo com o tipo de ação. Um clique longo forneceria uma dica do TalkBack "Toque duas vezes e mantenha pressionado para", seguida de um rótulo:
Row( modifier = Modifier .combinedClickable( onLongClickLabel = "Bookmark this article", onLongClick = { addToBookmarks() }, onClickLabel = "Open this article", onClick = { openArticle() }, ) ) {}
Em alguns casos, talvez você não tenha acesso direto ao modificador clickable (por exemplo, quando ele é definido em algum lugar em uma camada aninhada inferior),mas ainda queira mudar o rótulo do anúncio do padrão. Para fazer isso, divida a definição do
clickable da modificação do anúncio usando o modificador semantics
e defina o identificador de clique lá para modificar a representação da ação:
@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 } ) } ) }
Não é necessário passar a ação de clique duas vezes. As APIs Compose atuais, como
clickable ou Button, fazem isso por você. A lógica de fusão verifica
se o rótulo e a ação do modificador mais externos são usados para as informações
presentes. No exemplo anterior, o NestedArticleListItem transmite automaticamente
a ação de clique openArticle() à semântica clickable. Você pode
deixar a ação de clique nula na segunda ação do modificador de semântica. No entanto, o rótulo de clique é extraído do segundo modificador semântico onClick(label = "Open this document") porque não estava presente no primeiro.
Você pode encontrar cenários em que espera que a semântica dos filhos seja mesclada em uma semântica mãe, mas isso não acontece. Consulte Mesclar e limpar para mais informações.
Componentes personalizados
Ao criar um componente personalizado, revise a implementação de um
componente semelhante na biblioteca Material ou em outras bibliotecas do Compose. Em seguida, imite ou modifique o comportamento de acessibilidade conforme apropriado. Por exemplo, se você
substituir o Checkbox do Material Design por uma implementação própria, consulte
a implementação Checkbox atual para lembrar de adicionar o
modificador triStateToggleable, que
processa as propriedades de
acessibilidade do componente. Além disso, use os modificadores do Foundation
porque eles incluem considerações de acessibilidade integradas e práticas
do Compose abordadas nesta seção.
Você também encontra um exemplo de componente de alternância personalizado na seção Semântica clara e definida, além de informações mais detalhadas sobre como oferecer suporte à acessibilidade em componentes personalizados nas diretrizes da API.
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Acessibilidade no Compose
- Como testar o layout do Compose