Les API Material, Compose UI et Foundation implémentent et proposent de nombreuses pratiques d'accessibilité par défaut. Elles contiennent une sémantique intégrée qui suit leur rôle et leur fonction spécifiques. Cela signifie que la plupart des fonctionnalités d'accessibilité sont fournies sans effort supplémentaire ou presque.
L'utilisation des API appropriées pour l'objectif approprié signifie que les composants sont généralement fournis avec des comportements d'accessibilité prédéfinis qui couvrent les cas d'utilisation standards. Toutefois, vérifiez toujours si ces paramètres par défaut répondent à vos besoins en termes d'accessibilité. Sinon, Compose fournit des moyens de répondre à des exigences plus spécifiques.
Comprendre la sémantique et les modèles d'accessibilité par défaut dans les API Compose vous aide à les utiliser en tenant compte de l'accessibilité. Il vous aide également à prendre en charge l'accessibilité dans des composants plus personnalisés.
Tailles minimales des cibles tactiles
Tout élément à l'écran sur lequel un utilisateur peut cliquer ou appuyer, ou avec lequel il peut interagir, doit être assez grand pour permettre une interaction fiable. Lorsque vous dimensionnez ces éléments, assurez-vous de définir la taille minimale sur 48 dp de manière à respecter les consignes d'accessibilité de Material Design.
Pour les composants Material, comme Checkbox, RadioButton, Switch, Slider et Surface, définissez cette taille minimale en interne, mais seulement lorsque l'utilisateur peut agir dessus. Par exemple, lorsque le paramètre onCheckedChange d'une Checkbox a une valeur non nulle, la case à cocher inclut une marge intérieure dont la largeur et la hauteur sont d'au moins 48 dp.
@Composable private fun CheckableCheckbox() { Checkbox(checked = true, onCheckedChange = {}) }
Lorsque le paramètre onCheckedChange est défini sur nul, la marge intérieure n'est pas incluse, car il est impossible d'interagir directement avec le composant.
@Composable private fun NonClickableCheckbox() { Checkbox(checked = true, onCheckedChange = null) }
Lorsque vous implémentez des commandes de sélection telles que Switch, RadioButton ou Checkbox, vous élevez généralement le comportement cliquable au rang d'un conteneur parent en définissant le rappel de clic sur le composable sur null et en ajoutant un modificateur toggleable ou selectable au composable parent.
@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) } } }
Lorsque la taille d'un composable cliquable est inférieure à la taille minimale de la cible tactile, Compose augmente quand même les dimensions de cette zone. Pour ce faire, il étend la taille de la cible tactile au-delà des limites du composable.
L'exemple suivant contient une toute petite Box cliquable. La zone cible tactile est automatiquement étendue au-delà des limites de Box. Par conséquent, le fait d'appuyer à côté de Box déclenche quand même l'événement de clic.
@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) ) } }
Pour éviter tout chevauchement potentiel entre les zones tactiles des différents composables, utilisez toujours une taille minimale assez grande pour le composable. Dans l'exemple, cela implique d'utiliser le modificateur sizeIn pour définir la taille minimale du champ intérieur :
@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) ) } }
Éléments graphiques
Lorsque vous définissez un composable Image ou Icon, il n'existe pas de moyen automatique pour que le framework Android comprenne ce que l'application affiche. Vous devez transmettre une description textuelle de l'élément graphique.
Imaginez un écran sur lequel l'utilisateur peut partager la page active avec ses amis. Cet écran contient une icône de partage cliquable :
S'il ne dispose que de cette seule icône, le framework Android ne peut pas la décrire à un utilisateur malvoyant. Le framework Android a besoin d'une description textuelle supplémentaire de l'icône.
Le paramètre contentDescription décrit un élément graphique. Utilisez une chaîne localisée, car elle est visible par l'utilisateur.
@Composable private fun ShareButton(onClick: () -> Unit) { IconButton(onClick = onClick) { Icon( imageVector = Icons.Filled.Share, contentDescription = stringResource(R.string.label_share) ) } }
Certains éléments graphiques sont purement décoratifs, et vous ne souhaitez peut-être pas les communiquer à l'utilisateur. Lorsque vous définissez le paramètre contentDescription sur null, vous indiquez au framework Android que cet élément n'est associé à aucune action ni aucun état.
@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 est principalement destiné aux éléments graphiques, tels que les images. Les composants Material, tels que Button ou Text, et les comportements interactifs, tels que clickable ou toggleable, sont fournis avec d'autres sémantiques prédéfinies qui décrivent leur comportement intrinsèque et peuvent être modifiées à l'aide d'autres API Compose.
Éléments interactifs
Les API Material et Foundation Compose créent des éléments d'UI avec lesquels les utilisateurs peuvent interagir via les API de modification clickable et toggleable. Étant donné que les composants interactifs peuvent se composer de plusieurs éléments, clickable et toggleable fusionnent la sémantique de leurs enfants par défaut, de sorte que le composant est traité comme une seule entité logique.
Par exemple, un Button Material peut être constitué d'une icône enfant et de texte. Au lieu de traiter les enfants individuellement, un Button Material fusionne la sémantique de ses enfants par défaut, afin que les services d'accessibilité puissent les regrouper en conséquence :
De même, l'utilisation du modificateur clickable entraîne également la fusion de la sémantique des descendants d'un composable en une seule entité, qui est envoyée aux services d'accessibilité avec une représentation d'action correspondante :
Row( // Uses `mergeDescendants = true` under the hood modifier = Modifier.clickable { openArticle() } ) { Icon( painter = painterResource(R.drawable.ic_logo), contentDescription = "Open", ) Text("Accessibility in Compose") }
Vous pouvez également définir un onClickLabel spécifique sur l'élément parent cliquable pour fournir des informations supplémentaires aux services d'accessibilité et offrir une représentation plus soignée de l'action :
Row( modifier = Modifier .clickable(onClickLabel = "Open this article") { openArticle() } ) { Icon( painter = painterResource(R.drawable.ic_logo), contentDescription = "Open" ) Text("Accessibility in Compose") }
En utilisant TalkBack comme exemple, ce modificateur clickable et son libellé de clic permettraient à TalkBack de fournir un indice d'action "Appuyez deux fois pour ouvrir cet article", plutôt que le commentaire par défaut plus générique "Appuyez deux fois pour activer".
Ces commentaires varient en fonction du type d'action. Un appui prolongé fournit un indice TalkBack "Appuyez deux fois et maintenez pour", suivi d'un libellé :
Row( modifier = Modifier .combinedClickable( onLongClickLabel = "Bookmark this article", onLongClick = { addToBookmarks() }, onClickLabel = "Open this article", onClick = { openArticle() }, ) ) {}
Dans certains cas, vous n'aurez peut-être pas accès directement au modificateur clickable (par exemple, s'il est défini quelque part dans une couche imbriquée inférieure),mais vous souhaiterez tout de même modifier le libellé de l'annonce par rapport à la valeur par défaut. Pour ce faire, séparez la définition de clickable de la modification de l'annonce en utilisant le modificateur semantics et en définissant le libellé du clic à cet endroit, afin de modifier la représentation de l'action :
@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 } ) } ) }
Vous n'avez pas besoin de transmettre l'action de clic deux fois. Les API Compose existantes, telles que clickable ou Button, gèrent cela pour vous. La logique de fusion vérifie que le libellé et l'action du modificateur le plus externe sont pris en compte pour les informations présentes. Dans l'exemple précédent, NestedArticleListItem transmet automatiquement l'action de clic openArticle() à sa sémantique clickable. Vous pouvez laisser l'action de clic nulle dans la deuxième action du modificateur sémantique. Toutefois, le libellé de clic est extrait du deuxième modificateur sémantique onClick(label = "Open this document"), car il n'était pas présent dans le premier.
Vous pouvez rencontrer des scénarios dans lesquels vous vous attendez à ce que la sémantique des enfants soit fusionnée dans celle d'un parent, mais cela ne se produit pas. Pour en savoir plus, consultez Fusionner et effacer.
Composants personnalisés
Lorsque vous créez un composant personnalisé, examinez l'implémentation d'un composant similaire dans la bibliothèque Material ou d'autres bibliothèques Compose. Ensuite, imitez ou modifiez son comportement en matière d'accessibilité, le cas échéant. Par exemple, si vous remplacez la Checkbox Material par votre propre implémentation, l'examen de l'implémentation Checkbox existante vous rappellera d'ajouter le modificateur triStateToggleable, qui gère les propriétés d'accessibilité du composant. Utilisez également de manière intensive les modificateurs de base, car ils incluent des éléments d'accessibilité intégrés et les pratiques Compose existantes abordées dans cette section.
Vous trouverez également un exemple de composant à bascule personnalisé dans la section Effacer et définir la sémantique, ainsi que des informations plus détaillées sur la façon de prendre en charge l'accessibilité dans les composants personnalisés dans les Consignes de l'API.
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Accessibilité dans Compose
- Tester votre mise en page Compose