Lorsque les services d'accessibilité parcourent les éléments à l'écran, il est important que ces éléments soient regroupés, séparés ou même masqués avec la précision appropriée. Lorsque chaque composable de bas niveau à l'écran est mis en surbrillance indépendamment, les utilisateurs doivent beaucoup interagir pour se déplacer dans l'écran. Si les éléments sont fusionnés de manière excessive, les utilisateurs pourraient ne pas comprendre quels éléments vont ensemble. Si des éléments de l'écran sont purement décoratifs, ils peuvent être masqués des services d'accessibilité. Dans ce cas, vous pouvez utiliser les API Compose pour fusionner, effacer et masquer les sémantiques.
Sémantique de fusion
Lorsque vous appliquez un modificateur clickable
à un composable parent, Compose fusionne automatiquement tous les éléments enfants sous celui-ci. Pour comprendre comment les composants Compose Material et Foundation interactifs utilisent des stratégies de fusion par défaut, consultez la section Éléments interactifs.
Il est courant qu'un composant se compose de plusieurs composables. Ces composables peuvent former un groupe logique et chacun peut contenir des informations importantes, mais vous souhaitez peut-être que les services d'accessibilité les considèrent comme un seul élément.
Par exemple, imaginez un composable qui affiche l'avatar d'un utilisateur, son nom et d'autres informations supplémentaires:

Vous pouvez demander à Compose de fusionner ces éléments à l'aide du paramètre mergeDescendants
dans le modificateur de sémantique. De cette façon, les services d'accessibilité traitent le composant comme une entité, 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 fusionnant son contenu:

Chaque propriété sémantique a une stratégie de fusion définie. Par exemple, la propriété ContentDescription
ajoute toutes les valeurs descendantes ContentDescription
à une liste. Vous pouvez vérifier la stratégie de fusion d'une propriété sémantique en regardant son implémentation mergePolicy
dans SemanticsProperties.kt.
Les propriétés peuvent prendre la valeur parent ou enfant, fusionner les valeurs dans une liste ou une chaîne, ne pas autoriser la fusion du tout et générer une exception à la place, ou toute autre stratégie de fusion personnalisée.
Dans d'autres scénarios, vous vous attendez à ce que les sémantiques enfants soient fusionnées dans une sémantique parente, mais cela ne se produit pas. Dans l'exemple suivant, nous avons un élément parent de liste clickable
avec des éléments enfants, et nous nous attendons à ce que le parent les fusionne tous:

@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) } }
Lorsque l'utilisateur appuie sur l'élément clickable
Row
, l'article s'ouvre. En interne, il existe un BookmarkButton
permettant d'ajouter l'article aux favoris. Ce bouton imbriqué s'affiche comme non fusionné, tandis que le reste du contenu enfant de la ligne est fusionné:

Row
. L'arborescence non fusionnée contient des nœuds distincts pour chaque composable Text
.Par conception, certains composables ne sont pas automatiquement fusionnés sous un parent. Un parent ne peut pas fusionner ses enfants lorsque les enfants fusionnent également, soit en définissant mergeDescendants = true
explicitement, soit en étant des composants qui se fusionnent eux-mêmes, comme des boutons ou des éléments cliquables. Savoir comment certaines API fusionnent ou défient la fusion peut vous aider à déboguer certains comportements potentiellement inattendus.
Utilisez la fusion lorsque les éléments enfants constituent un groupe logique et pertinent sous leur parent. Toutefois, si les enfants imbriqués doivent être ajustés manuellement ou si leur propre sémantique doit être supprimée, d'autres API peuvent mieux répondre à vos besoins (par exemple, clearAndSetSemantics
).
Effacer et définir la sémantique
Si les informations sémantiques doivent être complètement effacées ou écrasées, utilisez l'API clearAndSetSemantics
.
Lorsqu'un composant doit effacer sa propre sémantique et celle de ses descendants, utilisez cette API avec un lambda vide. Lorsque sa sémantique doit être écrasée, incluez votre nouveau contenu dans le lambda.
Notez que lors de la suppression avec un lambda vide, les sémantiques effacées ne sont envoyées à aucun consommateur qui utilise ces informations, comme l'accessibilité, le remplissage automatique ou les tests. Lorsque vous remplacez du contenu par clearAndSetSemantics{/*semantic information*/}
, la nouvelle sémantique remplace toutes les sémantiques précédentes de l'élément et de ses descendants.
Voici un exemple de composant de bouton d'activation/de désactivation personnalisé, représenté par une ligne interactive avec une icône et du texte:
// 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?") } }
Bien que l'icône et le texte contiennent des informations sémantiques, ils n'indiquent pas ensemble que ce composant peut être activé/désactivé. La fusion n'est pas suffisante, car vous devez fournir des informations supplémentaires sur le composant.
Étant donné que l'extrait de code ci-dessus crée un composant de bouton d'activation/de désactivation personnalisé, vous devez ajouter la fonctionnalité de bouton d'activation/de désactivation, ainsi que les sémantiques stateDescription
, toggleableState
et role
. De cette façon, l'état du composant et l'action associée sont disponibles. Par exemple, TalkBack annonce "Appuyer deux fois pour activer/désactiver" au lieu de "Appuyer deux fois pour activer".
En effaçant les sémantiques d'origine et en définissant de nouvelles sémantiques plus descriptives, les services d'accessibilité peuvent désormais voir qu'il s'agit d'un composant à activer/désactiver qui peut changer d'état.
Lorsque vous utilisez clearAndSetSemantics
, tenez compte des points suivants:
- Étant donné que les services ne reçoivent aucune information lorsque cette API est définie, il est préférable de l'utiliser avec parcimonie.
- Les informations sémantiques peuvent être utilisées par les agents d'IA et les services similaires pour comprendre l'écran. Elles ne doivent donc être effacées que si nécessaire.
- Des sémantiques personnalisées peuvent être définies dans le lambda de l'API.
- L'ordre des modificateurs est important : cette API efface toutes les sémantiques qui se trouvent après l'endroit où elle est appliquée, quelles que soient les autres stratégies de fusion.
Sémantique masquée
Dans certains cas, les éléments n'ont pas besoin d'être envoyés aux services d'accessibilité. Leurs informations supplémentaires sont peut-être redondantes pour l'accessibilité, ou elles sont purement décoratives et non interactives. Dans ce cas, vous pouvez masquer des éléments avec l'API hideFromAccessibility
.
Les exemples suivants présentent des composants qui peuvent nécessiter d'être masqués: un filigrane redondant qui s'étend sur un composant et un caractère utilisé pour séparer de manière décorative les informations.
@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 •" ) }
L'utilisation de hideFromAccessibility
ici garantit que le filigrane et la décoration sont masqués des services d'accessibilité, mais conservent leur sémantique pour d'autres cas d'utilisation, comme les tests.
Répartition des cas d'utilisation
Vous trouverez ci-dessous un résumé des cas d'utilisation pour comprendre comment différencier clairement les API précédentes:
- Lorsque le contenu n'est pas destiné à être utilisé par les services d'accessibilité :
- Utilisez
hideFromAccessibility
lorsque le contenu est éventuellement décoratif ou redondant, mais doit tout de même être testé. - Utilisez
clearAndSetSemantics{}
avec un lambda vide lorsque la sémantique des parents et des enfants doit être effacée pour tous les services. - Utilisez
clearAndSetSemantics{/*content*/}
avec du contenu dans le lambda lorsque la sémantique d'un composant doit être définie manuellement.
- Utilisez
- Lorsque le contenu doit être traité comme une entité et que toutes les informations de ses enfants doivent être complètes :
- Utilisez des descendants sémantiques de fusion.

Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Accessibilité dans Compose
- [Material Design 2 dans Compose][19]
- Tester votre mise en page Compose