Dans Compose, vous pouvez enchaîner plusieurs modificateurs pour modifier l'apparence d'un composable. Ces chaînes de modificateur peuvent affecter les contraintes transmises aux composables, qui définissent des limites de largeur et de hauteur.
Cette page décrit comment les modificateurs en chaîne affectent les contraintes et, par conséquent, la mesure et le placement des composables.
Modificateurs dans l'arborescence de l'interface utilisateur
Pour comprendre comment les modificateurs s'influencent les uns les autres, il est utile de visualiser comment ils apparaissent dans l'arborescence de l'interface utilisateur, qui est générée pendant la phase de composition. Pour en savoir plus, consultez la section Composition.
Dans l'arborescence de l'UI, vous pouvez visualiser les modificateurs en tant que nœuds wrapper pour les nœuds de mise en page:
![Code des composables et des modificateurs, et leur représentation visuelle sous la forme d'une arborescence d'UI.](https://developer.android.google.cn/static/develop/ui/compose/images/layouts/constraints-modifiers/modifier-wrapping.png?authuser=4&hl=fr)
L'ajout de plusieurs modificateurs à un composable crée une chaîne de modificateurs. Lorsque vous enchaînez plusieurs modificateurs, chaque nœud de modificateur encapsule le reste de la chaîne et le nœud de mise en page qu'il contient. Par exemple, lorsque vous associez un clip
et un modificateur size
, le nœud de modificateur clip
encapsule le nœud de modificateur size
, qui encapsule ensuite le nœud de mise en page Image
.
Dans la phase de mise en page, l'algorithme qui parcourt l'arborescence reste le même, mais chaque nœud de modificateur est également visité. De cette façon, un modificateur peut modifier les exigences de taille et l'emplacement du nœud de modificateur ou de mise en page qu'il encapsule.
Comme le montre la figure 2, l'implémentation des composables Image
et Text
eux-mêmes consiste en une chaîne de modificateurs encapsulant un seul nœud de mise en page. Les implémentations de Row
et Column
sont simplement des nœuds de mise en page qui décrivent comment disposer leurs enfants.
![Arborescence d'origine, mais à présent, chaque nœud n'est qu'une mise en page simple avec de nombreux modificateurs encapsulant des nœuds autour.](https://developer.android.google.cn/static/develop/ui/compose/images/layouts/constraints-modifiers/composables-modifiers.png?authuser=4&hl=fr)
En résumé :
- Les modificateurs encapsulent un seul modificateur ou nœud de mise en page.
- Les nœuds de mise en page peuvent disposer plusieurs nœuds enfants.
Les sections suivantes décrivent comment utiliser ce modèle mental pour comprendre les enchaînements de modificateurs et comment il influence la taille des composables.
Contraintes lors de la phase de mise en page
La phase de mise en page suit un algorithme en trois étapes pour trouver la largeur, la hauteur et les coordonnées x et y de chaque nœud de mise en page:
- Mesurer les enfants: un nœud mesure ses enfants, le cas échéant.
- Décider de la taille: sur la base de ces mesures, un nœud décide de sa propre taille.
- Placer les enfants: chaque nœud enfant est placé par rapport à sa propre position.
Constraints
permet de trouver les tailles appropriées pour les nœuds lors des deux premières étapes de l'algorithme. Les contraintes définissent les limites minimale et maximale de largeur et de hauteur d'un nœud. Lorsque le nœud décide de sa taille, sa taille mesurée doit se situer dans cette plage de tailles.
Types de contraintes
Une contrainte peut être l'une des suivantes:
- Limité: le nœud a une largeur et une hauteur maximales et minimales.
![Contraintes liées de différentes tailles dans un conteneur.](https://developer.android.google.cn/static/develop/ui/compose/images/layouts/constraints-modifiers/bounded-constraints.png?authuser=4&hl=fr)
- Illimité: le nœud n'est soumis à aucune limite de taille. Les limites de largeur et de hauteur maximales sont définies sur l'infini.
![Contraintes illimitées dont la largeur et la hauteur sont définies sur l'infini. Les contraintes s'étendent au-delà du conteneur.](https://developer.android.google.cn/static/develop/ui/compose/images/layouts/constraints-modifiers/unbounded-constraints.png?authuser=4&hl=fr)
- Exact: le nœud doit respecter une taille exacte. Les limites minimale et maximale sont définies sur la même valeur.
![Contraintes exactes qui respectent une exigence exacte de taille au sein du conteneur.](https://developer.android.google.cn/static/develop/ui/compose/images/layouts/constraints-modifiers/exact-constraints.png?authuser=4&hl=fr)
- Combinaison: le nœud suit une combinaison des types de contraintes ci-dessus. Par exemple, une contrainte peut limiter la largeur tout en autorisant une hauteur maximale illimitée, ou définir une largeur exacte mais fournir une hauteur limitée.
![Deux conteneurs qui montrent des combinaisons de contraintes limitées et illimitées, et de largeurs et de hauteurs exactes.](https://developer.android.google.cn/static/develop/ui/compose/images/layouts/constraints-modifiers/combination-constraints.png?authuser=4&hl=fr)
La section suivante décrit comment ces contraintes sont transmises d'un parent à un enfant.
Comment les contraintes sont transmises du parent à l'enfant
Au cours de la première étape de l'algorithme décrit dans la section Contraintes lors de la phase de mise en page, les contraintes sont transmises du parent à l'enfant dans l'arborescence de l'interface utilisateur.
Lorsqu'un nœud parent mesure ses enfants, il fournit ces contraintes à chaque enfant pour leur indiquer la taille qu'ils peuvent avoir. Ensuite, lorsqu'il décide de sa propre taille, il respecte également les contraintes transmises par ses propres parents.
De manière générale, l'algorithme fonctionne comme suit:
- Pour décider de la taille qu'il souhaite réellement occuper, le nœud racine de l'arborescence de l'interface utilisateur mesure ses enfants et transmet les mêmes contraintes à son premier enfant.
- Si l'enfant est un modificateur qui n'a aucune incidence sur la mesure, il transmet les contraintes au modificateur suivant. Les contraintes sont transmises telles quelles dans la chaîne de modificateurs, sauf si un modificateur affectant la mesure est atteint. Les contraintes sont ensuite redimensionnées en conséquence.
- Une fois atteint un nœud qui ne comporte aucun enfant (appelé "nœud feuille"), il décide de sa taille en fonction des contraintes transmises et la renvoie à son parent.
- Le parent adapte ses contraintes en fonction des mesures de cet enfant et appelle son enfant suivant avec ces contraintes ajustées.
- Une fois que tous les enfants d'un parent ont été mesurés, le nœud parent décide de sa propre taille et la communique à son propre parent.
- De cette façon, l'ensemble de l'arborescence est balayé d'abord en profondeur. Au final, tous les nœuds ont décidé de leur taille, et l'étape de mesure est terminée.
Pour obtenir un exemple détaillé, consultez la vidéo Contraintes et ordre des modificateurs.
Modificateurs affectant les contraintes
Dans la section précédente, vous avez appris que certains modificateurs peuvent affecter la taille des contraintes. Les sections suivantes décrivent des modificateurs spécifiques qui ont un impact sur les contraintes.
Modificateur size
Le modificateur size
déclare la taille souhaitée pour le contenu.
Par exemple, l'arborescence d'interface utilisateur suivante doit être affichée dans un conteneur de 300dp
par 200dp
. Les contraintes sont limitées, ce qui permet des largeurs comprises entre 100dp
et 300dp
, et des hauteurs comprises entre 100dp
et 200dp
:
![Partie d'une arborescence d'interface utilisateur avec le modificateur de taille encapsulant un nœud de mise en page et la représentation des contraintes limitées définies par le modificateur de taille dans un conteneur.](https://developer.android.google.cn/static/develop/ui/compose/images/layouts/constraints-modifiers/size-modifier.png?authuser=4&hl=fr)
Le modificateur size
adapte les contraintes entrantes pour qu'elles correspondent à la valeur qui lui est transmise.
Dans cet exemple, la valeur est 150dp
:
![Identique à la figure 7, sauf que le modificateur de taille adapte les contraintes entrantes pour qu'elles correspondent à la valeur qui lui est transmise.](https://developer.android.google.cn/static/develop/ui/compose/images/layouts/constraints-modifiers/size-modifier-2.png?authuser=4&hl=fr)
size
ajuste les contraintes à 150dp
.Si la largeur et la hauteur sont inférieures à la plus petite limite de contrainte, ou supérieures à la plus grande limite de contrainte, le modificateur correspond autant que possible aux contraintes transmises, tout en respectant les contraintes transmises:
![Deux arborescences d'UI et leurs représentations correspondantes dans des conteneurs. Dans le premier cas, le modificateur de taille accepte les contraintes d'augmentation. Dans le second, le modificateur de taille s'adapte le plus près possible aux contraintes trop importantes, ce qui entraîne des contraintes qui remplissent le conteneur.](https://developer.android.google.cn/static/develop/ui/compose/images/layouts/constraints-modifiers/size-modifier-3.png?authuser=4&hl=fr)
size
respecte la contrainte transmise aussi fidèlement que possible.Notez que l'association de plusieurs modificateurs size
ne fonctionne pas. Le premier modificateur size
définit les contraintes minimale et maximale sur une valeur fixe. Même si le deuxième modificateur de taille demande une taille inférieure ou supérieure, il doit toujours respecter les limites exactes transmises, de sorte qu'il ne remplace pas ces valeurs:
![Chaîne de deux modificateurs de taille dans l'arborescence de l'interface utilisateur et sa représentation dans un conteneur, résultant de la première valeur transmise et non de la seconde.](https://developer.android.google.cn/static/develop/ui/compose/images/layouts/constraints-modifiers/size-modifier-4.png?authuser=4&hl=fr)
size
, dans laquelle la deuxième valeur transmise (50dp
) ne remplace pas la première valeur (100dp
).Modificateur requiredSize
Utilisez le modificateur requiredSize
au lieu de size
si vous souhaitez que votre nœud ignore les contraintes entrantes. Le modificateur requiredSize
remplace les contraintes entrantes et transmet la taille que vous spécifiez en tant que limites exactes.
Lorsque la taille est retransmise dans l'arborescence, le nœud enfant est centré dans l'espace disponible:
![La taille et le modificateur requiredSize enchaînés dans une arborescence d'UI, et la représentation correspondante dans un conteneur. Les contraintes du modificateur requiredSize remplacent les contraintes du modificateur de taille.](https://developer.android.google.cn/static/develop/ui/compose/images/layouts/constraints-modifiers/requiredsize-modifier.png?authuser=4&hl=fr)
requiredSize
ignorant les contraintes entrantes du modificateur size
.Modificateurs width
et height
Le modificateur size
adapte à la fois la largeur et la hauteur des contraintes. Avec le modificateur width
, vous pouvez définir une largeur fixe, mais laisser la hauteur indécis.
De même, avec le modificateur height
, vous pouvez définir une hauteur fixe, mais laisser la largeur indécis:
![Deux arborescences d'interface utilisateur, l'une avec le modificateur de largeur et sa représentation de conteneur, l'autre avec le modificateur de hauteur et sa représentation.](https://developer.android.google.cn/static/develop/ui/compose/images/layouts/constraints-modifiers/width-height-modifier.png?authuser=4&hl=fr)
width
et height
définissent respectivement une largeur et une hauteur fixes.Modificateur sizeIn
Le modificateur sizeIn
vous permet de définir des contraintes minimales et maximales exactes pour la largeur et la hauteur. Utilisez le modificateur sizeIn
si vous avez besoin d'exercer un contrôle précis sur les contraintes.
![Arborescence d'UI avec le modificateur sizeIn, avec des largeurs et des hauteurs minimales et maximales définies, et sa représentation dans un conteneur.](https://developer.android.google.cn/static/develop/ui/compose/images/layouts/constraints-modifiers/sizein-modifier.png?authuser=4&hl=fr)
sizeIn
avec minWidth
, maxWidth
, minHeight
et maxHeight
définis.Exemples
Cette section présente et explique le résultat de plusieurs extraits de code avec des modificateurs enchaînés.
Image( painterResource(R.drawable.hero), contentDescription = null, Modifier .fillMaxSize() .size(50.dp) )
Cet extrait de code produit le résultat suivant:
- Le modificateur
fillMaxSize
modifie les contraintes pour définir à la fois la largeur et la hauteur minimales sur la valeur maximale (300dp
en largeur et200dp
en hauteur). - Même si le modificateur
size
souhaite utiliser une taille de50dp
, il doit toujours respecter les contraintes minimales entrantes. Ainsi, le modificateursize
affichera également les limites de contrainte exactes de300
par200
, ignorant la valeur fournie dans le modificateursize
. Image
suit ces limites et indique une taille de300
par200
, qui est transmis tout en haut de l'arborescence.
Image( painterResource(R.drawable.hero), contentDescription = null, Modifier .fillMaxSize() .wrapContentSize() .size(50.dp) )
Cet extrait de code produit le résultat suivant:
- Le modificateur
fillMaxSize
adapte les contraintes pour définir à la fois la largeur et la hauteur minimales sur la valeur maximale (largeur300dp
et hauteur de200dp
). - Le modificateur
wrapContentSize
réinitialise les contraintes minimales. Ainsi, bien quefillMaxSize
entraînait des contraintes fixes,wrapContentSize
le réinitialise à des contraintes limitées. Le nœud suivant peut désormais occuper à nouveau tout l'espace ou être plus petit que la totalité de l'espace. - Le modificateur
size
définit les contraintes sur les limites minimale et maximale de50
. - Le
Image
est résolu en une taille de50
par50
, et le modificateursize
le transfère. - Le modificateur
wrapContentSize
possède une propriété spéciale. Elle prend son enfant et la place au centre des limites minimales disponibles qui lui ont été transmises. La taille qu'il communique à ses parents est donc égal aux limites minimales qui lui ont été transmises.
En combinant seulement trois modificateurs, vous pouvez définir une taille pour le composable et le centrer dans son parent.
Image( painterResource(R.drawable.hero), contentDescription = null, Modifier .clip(CircleShape) .padding(10.dp) .size(100.dp) )
Cet extrait de code produit le résultat suivant:
- Le modificateur
clip
ne modifie pas les contraintes.- Le modificateur
padding
réduit les contraintes maximales. - Le modificateur
size
définit toutes les contraintes sur100dp
. - Le
Image
respecte ces contraintes et indique une taille de100
par100dp
. - Le modificateur
padding
ajoute10dp
pour toutes les tailles. Il augmente donc la largeur et la hauteur indiquées de20dp
. - À présent, dans la phase de dessin, le modificateur
clip
agit sur un canevas de120
par120dp
. Elle crée ainsi un masque circulaire de cette taille. - Le modificateur
padding
insère ensuite son contenu de10dp
pour toutes les tailles, ce qui réduit la taille du canevas à100
de100dp
. - Le
Image
est dessiné dans ce canevas. L'image est rognée en fonction du cercle d'origine de120dp
. La sortie est donc un résultat non arrondi.
- Le modificateur