Une composition décrit l'interface utilisateur de votre application et est générée en exécutant composables. La composition est une arborescence composée des éléments suivants : composables qui décrivent votre UI.
À côté de la composition figure une arborescence parallèle, appelée sémantique arbre. Cette arborescence décrit votre UI d'une manière alternative compréhensible pour les services d'accessibilité et les tests d'infrastructure. Les services d'accessibilité utilisent l'arborescence pour décrire l'application aux utilisateurs ayant un besoin spécifique. Le framework de test utilise l'arborescence pour interagir avec votre application et effectuer des assertions à son sujet. L'arborescence sémantique ne contient pas sur la façon de dessiner vos composables, mais aussi sur la signification sémantique de vos composables ;
![Hiérarchie classique d'une UI et son arborescence sémantique](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-ui-tree.png?authuser=5&hl=fr)
Si votre application inclut des composables et des modificateurs tirés des bibliothèques Foundation et Material de Compose, l'arborescence sémantique est remplie et générée automatiquement. Toutefois, lorsque vous ajoutez des composables personnalisés de bas niveau, pour fournir manuellement sa sémantique. Votre arborescence pourrait ne pas refléter correctement ou complètement la signification des éléments affichés. Dans ce cas, vous pouvez adapter l'arborescence.
Prenons l'exemple de ce composable d'agenda personnalisé :
![Un composable d'agenda personnalisé avec des éléments "jour" sélectionnables](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-calendar.png?authuser=5&hl=fr)
Dans cet exemple, l'intégralité de l'agenda est implémentée en tant que composable unique de bas niveau, en utilisant le composable Layout
et en dessinant directement sur Canvas
.
Si vous ne faites rien d'autre, les services d'accessibilité ne recevront pas suffisamment
des informations sur le contenu du composable et la sélection de l'utilisateur dans
le calendrier. Par exemple, si un utilisateur clique sur le jour "17", le framework d'accessibilité reçoit uniquement les informations de description pour la commande d'agenda entière. Dans ce cas, le service d'accessibilité TalkBack
annonce "Agenda" ou, légèrement mieux, "Agenda d'avril" et l'utilisateur
se demander quel jour a été sélectionné. Pour rendre ce composable plus
accessibles, vous devrez ajouter manuellement
des informations sémantiques.
Propriétés sémantiques
Tous les nœuds de l'arborescence d'UI ayant une incidence sémantique disposent d'un nœud parallèle dans l'arborescence sémantique. Le nœud de l'arborescence sémantique contient les propriétés qui ont la signification du composable correspondant. Par exemple, Text
contient une propriété sémantique text
, car c'est la signification de
ce composable. Un élément Icon
contient une propriété contentDescription
(s'il est défini par
(développeur) qui transmet dans un texte la signification de Icon
.
Composables et modificateurs qui reposent sur la base de Compose
bibliothèque définissent déjà les propriétés pertinentes pour vous. Vous pouvez également définir
ou remplacez les propriétés vous-même avec les options semantics
et
modificateurs clearAndSetSemantics
. Par exemple, ajoutez des paramètres personnalisés
actions d'accessibilité à un nœud, fournissent un autre état
description d'un élément activable, ou indiquer qu'un certain texte
doit être considéré comme un en-tête.
Pour visualiser l'arborescence sémantique, utilisez l'outil d'inspection de la mise en page ou utilisez le
printToLog()
dans les tests. Cela permet d'afficher
Arborescence sémantique dans Logcat.
class MyComposeTest { @get:Rule val composeTestRule = createComposeRule() @Test fun MyTest() { // Start the app composeTestRule.setContent { MyTheme { Text("Hello world!") } } // Log the full semantics tree composeTestRule.onRoot().printToLog("MY TAG") } }
Le résultat est le suivant :
Printing with useUnmergedTree = 'false'
Node #1 at (l=0.0, t=63.0, r=221.0, b=120.0)px
|-Node #2 at (l=0.0, t=63.0, r=221.0, b=120.0)px
Text = '[Hello world!]'
Actions = [GetTextLayoutResult]
Réfléchissez à la manière dont les propriétés sémantiques transmettent la signification d'un composable. Envisagez d'utiliser
Switch
Voici comment il se présente :
![](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-switches.png?authuser=5&hl=fr)
Pour décrire la signification de cet élément, vous pouvez dire ceci: "Ceci est un bouton bascule, qui se trouve dans son état "Activé" de l'état. Vous pouvez cliquer dessus d'interagir avec elle."
C'est précisément ce à quoi servent les propriétés sémantiques. Le nœud sémantique de cet élément Switch (Bouton bascule) contient les propriétés suivantes, telles qu'elles sont représentées par la Outil d'inspection de la mise en page:
![Outil d'inspection de la mise en page affichant les propriétés sémantiques d'un composable Switch (Bouton bascule)](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-layout-inspector-switch.png?authuser=5&hl=fr)
Role
indique le type d'élément. L'StateDescription
explique comment
l'option "Activé" doit être référencé. Par défaut, il s'agit d'une version localisée
avec le mot "Activé", mais vous pouvez préciser
sur le contexte. ToggleableState
correspond à l'état actuel du commutateur. La
La propriété OnClick
fait référence à la méthode utilisée pour interagir avec cet élément. Pour
pour obtenir la liste complète des propriétés sémantiques, consultez la SemanticsProperties
. Pour obtenir la liste complète des actions d'accessibilité possibles, consultez l'objet SemanticsActions
.
Le suivi des propriétés sémantiques de chaque composable dans votre application offre tout un éventail de possibilités puissantes. Voici quelques exemples :
- TalkBack utilise les propriétés pour lire à voix haute ce qui est affiché à l'écran. et permet à l'utilisateur d'interagir facilement avec elle. Pour le composable "Switch" (Bouton bascule), TalkBack peut dites : "Activé, Bouton bascule appuyez deux fois pour activer/désactiver". L'utilisateur peut appuyer deux fois sur son à l'écran pour désactiver le bouton.
-
Le framework de test utilise les propriétés pour rechercher des nœuds, interagir avec eux et effectuer des assertions. Voici un exemple de test pour le bouton bascule:
val mySwitch = SemanticsMatcher.expectValue( SemanticsProperties.Role, Role.Switch ) composeTestRule.onNode(mySwitch) .performClick() .assertIsOff()
Arborescence sémantique fusionnée et non fusionnée
Comme mentionné précédemment, chaque composable de l'arborescence de l'UI peut avoir des propriétés sémantiques définies sur zéro ou plus. Lorsqu'aucune propriété sémantique n'est définie pour un composable, n'est pas inclus dans l'arborescence sémantique. Ainsi, l'arborescence sémantique ne contient que les nœuds qui ont une incidence sémantique. Cependant, pour indiquer la signification correcte des informations affichées à l'écran, il est parfois utile de fusionner certaines sous-arborescences de nœuds et de les traiter comme un seul et même élément. Ainsi, vous pouvez raisonner sur un ensemble de nœuds dans son ensemble, au lieu de traiter chaque un nœud descendant individuellement. En règle générale, chaque nœud de cette arborescence représente un élément sélectionnable lorsque vous utilisez des services d'accessibilité.
Button
est un exemple de ce type de composable. Vous pouvez raisonner sur un bouton
comme élément unique, même s'il peut contenir plusieurs nœuds enfants:
Button(onClick = { /*TODO*/ }) { Icon( imageVector = Icons.Filled.Favorite, contentDescription = null ) Spacer(Modifier.size(ButtonDefaults.IconSpacing)) Text("Like") }
Dans l'arborescence sémantique, les propriétés des descendants du bouton sont fusionnées. Le bouton se présente sous la forme d'un nœud feuille unique dans l'arborescence:
![Représentation sémantique à feuille unique fusionnée](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-merged-single-leaf.png?authuser=5&hl=fr)
Les composables et les modificateurs peuvent indiquer qu'ils souhaitent fusionner les propriétés sémantiques de leurs descendants en appelant Modifier.semantics
(mergeDescendants = true) {}
. Si vous définissez cette propriété sur true
, vous indiquez que les propriétés sémantiques doivent être fusionnées. Dans l'exemple Button
, Button
le composable utilise le modificateur clickable
en interne, qui inclut cette
Modificateur semantics
. Par conséquent, les nœuds descendants du bouton sont fusionnés.
Lisez la documentation sur l'accessibilité pour savoir quand modifier
de fusion dans votre composable.
Plusieurs modificateurs et composables des bibliothèques Foundation et Material Compose disposent de cette propriété. Par exemple, les modificateurs clickable
et toggleable
fusionnent automatiquement leurs descendants. De plus, le composable ListItem
fusionnera ses descendants.
Inspecter les arbres
L'arbre sémantique est en fait deux arbres différents. La sémantique fusionnée
tree, qui fusionne les nœuds descendants lorsque mergeDescendants
est défini sur true
.
Il existe également une arborescence sémantique non fusionnée, qui n'applique pas la fusion,
conserve chaque nœud intact. Les services d'accessibilité utilisent l'arborescence non fusionnée et appliquent
leurs propres algorithmes de fusion, en tenant compte du mergeDescendants
. Le framework de test utilise l'arborescence fusionnée par défaut.
Vous pouvez inspecter ces deux arborescences avec la méthode printToLog()
. Par défaut, et comme dans
dans les exemples précédents, l'arborescence fusionnée est consignée. Pour imprimer l'arborescence non fusionnée
Définissez plutôt le paramètre useUnmergedTree
de l'outil de mise en correspondance onRoot()
sur
true
:
composeTestRule.onRoot(useUnmergedTree = true).printToLog("MY TAG")
L'outil d'inspection de la mise en page vous permet d'afficher à la fois la sémantique fusionnée et la sémantique non fusionnée en sélectionnant l'option de votre choix dans le filtre de la vue:
![Options d'affichage de l'outil d'inspection de la mise en page permettant d'afficher à la fois l'arborescence sémantique fusionnée et l'arborescence sémantique non fusionnée](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-layout-inspector-menu.png?authuser=5&hl=fr)
Pour chaque nœud de votre arborescence, l'outil d'inspection de mise en page affiche la sémantique fusionnée et la sémantique définie sur ce nœud dans le panneau des propriétés :
![Propriétés sémantiques fusionnées et définies](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-merged-and-set.png?authuser=5&hl=fr)
Par défaut, les outils de mise en correspondance du framework de test utilisent l'arborescence sémantique fusionnée.
C'est pourquoi vous pouvez interagir avec un Button
en faisant correspondre le texte qu'il contient
comme suit:
composeTestRule.onNodeWithText("Like").performClick()
Remplacez ce comportement en définissant le paramètre useUnmergedTree
de
à true
, comme avec onRoot
.
Comportement de la fusion
Lorsqu'un composable indique que ses descendants doivent être fusionnés, comment cette fusion se produit-elle exactement ?
Chaque propriété sémantique a une stratégie de fusion définie. Par exemple,
La propriété ContentDescription
ajoute toutes les valeurs ContentDescription descendantes à une
liste. Vérifier la stratégie de fusion d'une propriété sémantique en vérifiant sa
Implémentation de mergePolicy
dans SemanticsProperties.kt
. Les établissements peuvent
prend la valeur parent ou enfant, les fusionner dans une liste
n'autorise pas la fusion et génère une exception à la place, ou toute autre
une stratégie de fusion personnalisée.
Il est important de noter que les descendants qui ont eux-mêmes défini mergeDescendants
= true
ne sont pas inclus dans la fusion. Examinons un exemple:
![Élément de liste avec une image, du texte et une icône de favori](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-dagger.png?authuser=5&hl=fr)
Voici un élément de liste cliquable. Lorsque l'utilisateur appuie sur la ligne, il accède à la page de détails de l'article et peut le lire. À l'intérieur de l'élément de liste, il y a un bouton pour ajouter l'article aux favoris, ce qui élément cliquable imbriqué, de sorte que le bouton s'affiche séparément dans le arborescence fusionnée. Le reste du contenu de la ligne est fusionné :
![L'arborescence fusionnée contient plusieurs textes d'une liste au sein du nœud "Ligne". L'arborescence non fusionnée contient des nœuds distincts pour chaque composable Text.](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-merged-vs-unmerged.png?authuser=5&hl=fr)
Adapter l'arborescence sémantique
Comme indiqué précédemment, vous pouvez remplacer ou effacer certaines propriétés sémantiques ou modifier le comportement de fusion de l'arborescence. Cela est particulièrement pertinent lorsque vous créez vos propres composants personnalisés. Si vous ne définissez pas et le comportement de fusion, il est possible que votre application ne soit pas accessible et que les tests se comportent différemment de ce à quoi vous vous attendiez. Pour en savoir plus sur certains cas d'utilisation courants où vous devez adapter l'arborescence sémantique, consultez les documentation. Pour en savoir plus sur les tests, consultez la section Tests guide de démarrage.
Ressources supplémentaires
- Accessibilité:concepts et concepts essentiels techniques communes au développement d'applications Android
- Créer des applications accessibles:étapes clés pour rendre votre application plus accessible
- Principes d'amélioration d'une application accessibilité:principes clés pour à garder à l'esprit lorsque vous cherchez à rendre votre application plus accessible
- Tests d'accessibilité: Tester les principes et les outils d'accessibilité sur Android
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Accessibilité dans Compose
- Material Design 2 dans Compose
- Tester votre mise en page Compose