Pour aider les personnes ayant des besoins d'accessibilité à utiliser votre application, concevez-la de sorte qu'elle réponde aux principales exigences d'accessibilité.
Définissez une taille minimale pour les zones 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 afin de respecter les consignes d'accessibilité Material Design.
Les composants Material, tels que Checkbox
, RadioButton
, Switch
, Slider
et Surface
, définissent cette taille minimale en interne, mais uniquement lorsque le composant peut recevoir des actions de l'utilisateur. Par exemple, lorsque le paramètre onCheckedChange
d'un élément Checkbox
est défini sur 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 "null", 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 vers un conteneur parent, définissez le rappel de clic du composable sur null
et ajoutez 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 zone cible tactile, Compose augmente quand même les dimensions de cette zone. Pour ce faire, la taille de la zone cible tactile est étendue en dehors des limites du composable.
L'exemple suivant contient un très petit élément Box
cliquable. La zone cible tactile est automatiquement étendue au-delà des limites de la Box
. Par conséquent, 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 éventuel entre les zones tactiles de différents composables, utilisez toujours une taille minimale suffisamment grande pour le composable. Dans cet exemple, cela impliquerait d'utiliser le modificateur sizeIn
pour définir la taille minimale de la zone intérieure:
@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) ) } }
Ajouter des étiquettes de clic
Vous pouvez utiliser une étiquette de clic pour ajouter une signification sémantique au comportement de clic d'un composable. Les libellés de clic décrivent ce qui se passe lorsque l'utilisateur interagit avec le composable. Les services d'accessibilité utilisent des libellés de clic pour décrire l'application aux utilisateurs ayant des besoins spécifiques.
Définissez le libellé du clic en transmettant un paramètre dans le modificateur 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 ) ) { // .. } }
Si vous n'avez pas accès au modificateur cliquable, définissez le libellé de clic dans le modificateur 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) } ) { // .. } }
Décrire les éléments visuels
Lorsque vous définissez un composable Image
ou Icon
, le framework Android ne dispose d'aucun moyen automatique de comprendre ce que l'application affiche. Vous devez transmettre une description textuelle de l'élément visuel.
Imaginez un écran sur lequel l'utilisateur peut partager la page active avec ses amis. Cet écran contient une icône de partage cliquable :
En se basant uniquement sur l'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 visuel. 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 visuels 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) ) }
C'est à vous de décider si un élément visuel spécifique a besoin d'une contentDescription
. Demandez-vous si l'élément transmet les informations dont l'utilisateur aura besoin pour effectuer sa tâche. Si ce n'est pas le cas, il est préférable de laisser la description de côté.
Fusionner des éléments
Les services d'accessibilité tels que TalkBack et Switch Access permettent aux utilisateurs de déplacer le curseur sur les différents éléments à l'écran. Il est important que les éléments soient sélectionnés avec la précision appropriée. Lorsque chaque composable de bas niveau sur l'écran est sélectionné indépendamment, les utilisateurs doivent beaucoup interagir pour se déplacer sur l'écran. Si les éléments fusionnent de manière trop agressive, les utilisateurs risquent de ne pas comprendre quels éléments vont ensemble.
Lorsque vous appliquez un modificateur clickable
à un composable, Compose fusionne automatiquement tous les éléments qu'il contient. Cela s'applique également à ListItem
. Les éléments d'un élément de liste fusionnent et les services d'accessibilité les voient comme un seul élément.
Il se peut qu'un ensemble de composables constitue un groupe logique, mais que ce groupe ne soit pas cliquable ou ne fasse pas partie d'un élément de liste. Vous souhaitez toujours que les services d'accessibilité les voient comme un seul élément. Par exemple, imaginez un composable qui affiche l'avatar d'un utilisateur, son nom et des informations supplémentaires:
Vous pouvez autoriser Compose à fusionner ces éléments à l'aide du paramètre mergeDescendants
dans le modificateur semantics
. De cette façon, les services d'accessibilité ne sélectionnent que l'élément fusionné, et toutes les propriétés sémantiques des descendants sont fusionnées.
@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") } } }
Les services d'accessibilité se concentrent désormais sur l'ensemble du conteneur en une seule fois, en fusionnant leur contenu:
Ajouter des actions personnalisées
Examinez l'élément de liste suivant :
Lorsque vous utilisez un lecteur d'écran tel que TalkBack pour entendre ce qui est affiché à l'écran, celui-ci sélectionne d'abord l'élément entier, puis l'icône des favoris.
Dans une longue liste, cela peut devenir très répétitif. Une meilleure approche consiste à définir une action personnalisée qui permet à un utilisateur d'ajouter l'élément à ses favoris. N'oubliez pas que vous devez également supprimer explicitement le comportement de l'icône de favori pour vous assurer qu'elle n'est pas sélectionnée par le service d'accessibilité. Pour ce faire, utilisez le modificateur 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 { } ) } }
Décrire l'état d'un élément
Un composable peut définir une stateDescription
pour la sémantique utilisée par le framework Android pour lire l'état dans lequel se trouve le composable. Par exemple, un composable activable peut être à l'état "coché" ou "non coché". Dans certains cas, vous pouvez remplacer les libellés de description d'état par défaut utilisés par Compose. Pour ce faire, spécifiez explicitement les étiquettes de description d'état avant de définir un composable comme activable:
@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() } ) ) { /* ... */ } }
Définir des titres
Les applications affichent parfois beaucoup de contenu sur un même écran dans un conteneur déroulant. Par exemple, un écran peut afficher le contenu complet d'un article que l'utilisateur lit :
Les utilisateurs ayant des besoins en matière d'accessibilité ont des difficultés à naviguer sur un tel écran. Pour faciliter la navigation, indiquez quels éléments sont des en-têtes. Dans l'exemple précédent, chaque titre de sous-section pourrait être défini comme un titre pour l'accessibilité. Certains services d'accessibilité, tels que TalkBack, permettent aux utilisateurs de passer directement d'un titre à l'autre.
Dans Compose, vous indiquez qu'un composable est un titre en définissant sa propriété semantics
:
@Composable private fun Subsection(text: String) { Text( text = text, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.semantics { heading() } ) }
Gérer les composables personnalisés
Chaque fois que vous remplacez certains composants Material de votre application par des versions personnalisées, vous devez garder à l'esprit les considérations d'accessibilité.
Supposons que vous remplacez le Checkbox
Material par votre propre implémentation.
Vous pouvez oublier d'ajouter le modificateur triStateToggleable
, qui gère les propriétés d'accessibilité de ce composant.
En règle générale, examinez l'implémentation du composant dans la bibliothèque Material et imitez tous les comportements d'accessibilité que vous pouvez trouver. Utilisez également de manière intensive les modificateurs de base plutôt que les modificateurs de niveau de l'interface utilisateur, car ils incluent des éléments d'accessibilité prêts à l'emploi.
Testez l'implémentation de vos composants personnalisés avec plusieurs services d'accessibilité pour vérifier leur comportement.
Ressources supplémentaires
- Accessibilité:concepts et techniques essentiels communs à tout le développement d'applications Android
- Créer des applications accessibles:étapes clés à suivre pour rendre votre application plus accessible
- Principes pour améliorer l'accessibilité des applications:principes clés à garder à l'esprit lorsque vous cherchez à rendre votre application plus accessible.
- Testing for Accessibility (Tests d'accessibilité) : principes et outils de test pour l'accessibilité sur Android.