À medida que os serviços de acessibilidade navegam pelos elementos na tela, é importante que eles sejam agrupados, separados ou até mesmo ocultados na granularidade certa. Quando cada elemento combinável de baixo nível na tela é destacado de forma independente, os usuários precisam interagir muito para navegar pela tela. Se os elementos forem combinados de forma exagerada, os usuários podem não compreender quais elementos estão agrupados. Se houver elementos na tela que sejam puramente decorativos, eles poderão ser ocultados dos serviços de acessibilidade. Nesses casos, use as APIs do Compose para mesclar, limpar e ocultar a semântica.
Semântica de mesclagem
Ao aplicar um modificador clickable a um elemento combinável pai, o Compose
mescla automaticamente todos os elementos filhos abaixo dele. Para entender como
os componentes interativos do Compose Material e do Foundation usam estratégias de mesclagem
por padrão, consulte a seção Elementos interativos.
É comum que um componente seja composto por vários elementos combináveis. Esses combináveis podem formar um grupo lógico e cada um pode conter informações importantes, mas talvez você ainda queira que os serviços de acessibilidade os vejam como um único elemento.
Por exemplo, imagine um elemento combinável que mostre o avatar de um usuário, o nome e algumas informações complementares:
Você pode permitir que o Compose mescle esses elementos usando o parâmetro mergeDescendants
no modificador de semântica. Dessa forma, os serviços de acessibilidade tratam o
componente como uma entidade, e todas as propriedades semânticas dos descendentes são
mescladas:
@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") } } }
Agora, os serviços de acessibilidade têm como foco o contêiner todo e mesclam o conteúdo:
Cada propriedade semântica tem uma estratégia de mesclagem definida. Por exemplo, a propriedade
ContentDescription adiciona todos os valores ContentDescription descendentes
a uma lista. Para verificar a estratégia de mesclagem de uma propriedade de semântica,
confira a implementação de mergePolicy em SemanticsProperties.kt.
As propriedades podem assumir o valor pai ou filho, mesclar os valores em uma lista
ou string, não permitir a mesclagem e gerar uma exceção ou qualquer
outra estratégia de mesclagem personalizada.
Há outros cenários em que você espera que a semântica filha seja mesclada com
uma semântica mãe, mas isso não acontece. No exemplo a seguir, temos um item de lista pai clickable com elementos filhos, e podemos esperar que o pai mescle todos eles:
@Composable private fun ArticleListItem( openArticle: () -> Unit, addToBookmarks: () -> Unit, ) { Row(modifier = Modifier.clickable { openArticle() }) { // Merges with parent clickable: Icon( painter = painterResource(R.drawable.ic_logo), contentDescription = "Article thumbnail" ) ArticleDetails() // Defies the merge due to its own clickable: BookmarkButton(onClick = addToBookmarks) } }
Quando o usuário pressiona o item Row de clickable, o artigo é aberto. Dentro
dele, há um BookmarkButton para adicionar o artigo aos favoritos. Esse botão aninhado
aparece como não mesclado, enquanto o restante do conteúdo filho dentro da linha é
mesclado:
Row. A árvore sem mesclagem contém nós separados para cada elemento combinável Text.Alguns elementos de composição não são mesclados automaticamente em um pai, por padrão. Um
elemento pai não pode mesclar os filhos quando eles também estão sendo mesclados, seja
pela configuração explícita de mergeDescendants = true ou por serem componentes que
se mesclam, como botões ou elementos clicáveis. Saber como determinadas APIs se mesclam ou
não pode ajudar a depurar alguns comportamentos potencialmente inesperados.
Use a mesclagem quando os elementos filhos constituírem um grupo lógico e sensível
no elemento pai. No entanto, se os filhos aninhados precisarem de ajuste manual ou remoção
da própria semântica, outras APIs podem ser mais adequadas às suas necessidades (por exemplo,
clearAndSetSemantics).
Limpar e definir semântica
Se as informações semânticas precisarem ser completamente apagadas ou substituídas, uma
API eficiente para usar é a clearAndSetSemantics.
Quando um componente precisa que a própria semântica e a dos descendentes sejam limpas, use essa API com uma lambda vazia. Quando a semântica precisar ser substituída, inclua o novo conteúdo dentro do lambda.
Ao limpar com uma lambda vazia, a semântica limpa não é
enviada para nenhum consumidor que use essas informações, como acessibilidade, preenchimento automático
ou testes. Ao substituir o conteúdo por
clearAndSetSemantics{/*semantic information*/}, a nova semântica substitui todas as
semânticas anteriores do elemento e dos descendentes dele.
Confira um exemplo de componente de alternância personalizado, representado por uma linha interativa com um ícone e um texto:
// Developer might intend this to be a toggleable. // Using `clearAndSetSemantics`, on the Row, a clickable modifier is applied, // a custom description is set, and a Role is applied. @Composable fun FavoriteToggle() { val checked = remember { mutableStateOf(true) } Row( modifier = Modifier .toggleable( value = checked.value, onValueChange = { checked.value = it } ) .clearAndSetSemantics { stateDescription = if (checked.value) "Favorited" else "Not favorited" toggleableState = ToggleableState(checked.value) role = Role.Switch }, ) { Icon( imageVector = Icons.Default.Favorite, contentDescription = null // not needed here ) Text("Favorite?") } }
Embora o ícone e o texto tenham algumas informações semânticas, juntos eles não indicam que esse componente é alternável. A mesclagem não é suficiente porque você precisa fornecer mais informações sobre o componente.
Como o snippet acima cria um componente de alternância personalizado, é necessário adicionar
a capacidade de alternância, bem como as semânticas stateDescription,
toggleableState e role. Dessa forma, o status
do componente e a ação associada ficam disponíveis. Por exemplo, o TalkBack anuncia
"Toque duas vezes para alternar" em vez de "Toque duas vezes para ativar".
Ao limpar a semântica original e definir uma nova, mais descritiva, os serviços de acessibilidade agora podem ver que esse é um componente alternável que pode mudar de estado.
Ao usar clearAndSetSemantics, considere o seguinte:
- Como os serviços não recebem informações quando essa API é definida, é melhor
usá-la com moderação.
- As informações de semântica podem ser usadas por agentes de IA e serviços semelhantes para entender a tela. Por isso, elas só devem ser limpas quando necessário.
- A semântica personalizada pode ser definida na lambda da API.
- A ordem dos modificadores é importante. Essa API limpa todas as semânticas que estão depois de onde ela é aplicada, independentemente de outras estratégias de mesclagem.
Ocultar semântica
Em alguns cenários, os elementos não precisam ser enviados aos serviços de acessibilidade.
Talvez as informações adicionais sejam redundantes para a acessibilidade
ou sejam puramente decorativas e não interativas. Nesses casos, é possível
ocultar elementos com a API hideFromAccessibility.
Nos exemplos a seguir, há componentes que podem precisar ser ocultados: uma marca-d'água redundante que abrange um componente e um caractere usado para separar informações de forma decorativa.
@Composable fun WatermarkExample( watermarkText: String, content: @Composable () -> Unit, ) { Box { WatermarkedContent() // Mark the watermark as hidden to accessibility services. WatermarkText( text = watermarkText, color = Color.Gray.copy(alpha = 0.5f), modifier = Modifier .align(Alignment.BottomEnd) .semantics { hideFromAccessibility() } ) } } @Composable fun DecorativeExample() { Text( modifier = Modifier.semantics { hideFromAccessibility() }, text = "A dot character that is used to decoratively separate information, like •" ) }
O uso de hideFromAccessibility aqui garante que a marca d'água e a decoração fiquem
ocultas dos serviços de acessibilidade, mas ainda mantenham a semântica para outros
casos de uso, como testes.
Detalhamento dos casos de uso
Confira a seguir um resumo dos casos de uso para entender como diferenciar claramente as APIs anteriores:
- Quando o conteúdo não é destinado ao uso por serviços de acessibilidade:
- Use
hideFromAccessibilityquando o conteúdo for possivelmente decorativo ou redundante, mas ainda precisar ser testado. - Use
clearAndSetSemantics{}com uma lambda vazia quando a semântica de pai e filhos precisar ser limpa para todos os serviços. - Use
clearAndSetSemantics{/*content*/}com conteúdo dentro da lambda quando a semântica de um componente precisar ser definida manualmente.
- Use
- Quando o conteúdo precisa ser tratado como uma única entidade e precisa de todas as informações dos filhos para ser completo:
- Use descendentes semânticos de mesclagem.
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Acessibilidade no Compose
- [Material Design 2 no Compose][19]
- Como testar o layout do Compose