Contraintes et ordre des modificateurs

Dans Compose, vous pouvez enchaîner plusieurs modificateurs pour modifier l'apparence d'un composable. Ces chaînes de modificateurs peuvent avoir une incidence sur les contraintes transmises aux composables, qui définissent les limites de largeur et de hauteur.

Cette page explique comment les modificateurs en chaîne affectent les contraintes et, à leur tour, la mesure et l'emplacement des composables.

Modificateurs dans l'arborescence de l'UI

Pour comprendre comment les modificateurs s'influencent les uns les autres, il est utile de visualiser leur apparence dans l'arborescence de l'UI, 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 de wrapper pour les nœuds de mise en page:

Code pour les composables et les modificateurs, ainsi que leur représentation visuelle sous forme d'arborescence d'UI.
Figure 1. Modificateurs encapsulant des nœuds de mise en page dans l'arborescence de l'UI.

Si vous ajoutez plusieurs modificateurs à un composable, une chaîne de modificateurs est créée. 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. Par exemple, lorsque vous enchaînez un modificateur 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.

Lors de 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 manière, un modificateur peut modifier les exigences de taille et l'emplacement du modificateur ou du nœud de mise en page qu'il encapsule.

Comme le montre la figure 2, l'implémentation des composables Image et Text consiste en une chaîne de modificateurs encapsulant un seul nœud de mise en page. Les implémentations de Row et Column ne sont que des nœuds de mise en page qui décrivent comment mettre en page leurs enfants.

Structure arborescente d'avant, mais chaque nœud n'est plus qu'une mise en page simple, entourée de nombreux nœuds de modification.
Figure 2. Même structure arborescente que dans la figure 1, mais avec des composables dans l'arborescence de l'UI visualisés sous forme de chaînes de modificateurs.

En résumé :

  • Les modificateurs encapsulent un seul modificateur ou un seul nœud de mise en page.
  • Les nœuds de mise en page peuvent mettre en page plusieurs nœuds enfants.

Les sections suivantes décrivent comment utiliser ce modèle mental pour raisonner sur l'enchaînement des modificateurs et comment cela 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 déterminer la largeur, la hauteur et les coordonnées x et y de chaque nœud de mise en page:

  1. Mesurer les enfants: un nœud mesure ses enfants, le cas échéant.
  2. Déterminer sa propre taille: sur la base de ces mesures, un nœud détermine sa propre taille.
  3. Placer les enfants: chaque nœud enfant est placé par rapport à la position de son propre nœud.

Constraints aide à trouver les tailles appropriées pour les nœuds au cours des deux premières étapes de l'algorithme. Les contraintes définissent les limites minimales et maximales pour la largeur et la hauteur d'un nœud. Lorsque le nœud décide de sa taille, sa taille mesurée doit se trouver dans cette plage de tailles.

Types de contraintes

Une contrainte peut être l'une des valeurs suivantes:

  • Limité: le nœud a une largeur et une hauteur maximales et minimales.
Contraintes bornées de différentes tailles dans un conteneur.
Figure 3 Contraintes limitées.
  • Illimité: la taille du nœud n'est pas limitée. 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.
Figure 4 Contraintes illimitées.
  • Exact: le nœud doit respecter une exigence de taille exacte. Les limites minimale et maximale sont définies sur la même valeur.
Contraintes exactes qui respectent une exigence de taille exacte dans le conteneur.
Figure 5 Contraintes exactes.
  • 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 affichent des combinaisons de contraintes limitées et illimitées, ainsi que des largeurs et des hauteurs exactes.
Figure 6. Combinaisons de contraintes limitées et illimitées, ainsi que de largeurs et de hauteurs exactes.

La section suivante décrit comment ces contraintes sont transmises d'un parent à un enfant.

Comment les contraintes sont transmises du parent à l'enfant

Lors 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'UI.

Lorsqu'un nœud parent mesure ses enfants, il fournit ces contraintes à chacun d'eux pour leur indiquer la taille maximale ou minimale 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:

  1. Pour déterminer la taille qu'il souhaite réellement occuper, le nœud racine de l'arborescence de l'UI mesure ses enfants et transmet les mêmes contraintes à son premier enfant.
  2. Si l'enfant est un modificateur qui n'a pas d'incidence sur la mesure, il transmet les contraintes au modificateur suivant. Les contraintes sont transmises à la chaîne de modificateurs telles quelles, sauf si un modificateur qui a un impact sur la mesure est atteint. Les contraintes sont ensuite redimensionnées en conséquence.
  3. Une fois qu'un nœud sans enfants (appelé "nœud feuille") est atteint, il détermine sa taille en fonction des contraintes transmises et renvoie cette taille résolue à son parent.
  4. Le parent adapte ses contraintes en fonction des mesures de cet enfant et appelle son enfant suivant avec ces contraintes ajustées.
  5. 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.
  6. De cette manière, l'ensemble de l'arborescence est parcouru en profondeur. À terme, tous les nœuds ont déterminé leurs tailles et l'étape de mesure est terminée.

Pour obtenir un exemple détaillé, regardez 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 les modificateurs spécifiques qui ont une incidence sur les contraintes.

Modificateur size

Le modificateur size déclare la taille préférée du contenu.

Par exemple, l'arborescence de l'UI suivante doit être affichée dans un conteneur 300dp par 200dp. Les contraintes sont limitées, ce qui permet de définir des largeurs comprises entre 100dp et 300dp, et des hauteurs comprises entre 100dp et 200dp:

Portion d'un arbre d'UI 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.
Figure 7 : Contraintes limitées dans l'arborescence de l'UI et représentation dans un conteneur.

Le modificateur size adapte les contraintes entrantes pour qu'elles correspondent à la valeur qui lui est transmise. Dans cet exemple, la valeur est 150dp:

Il s'agit de la même figure 7, à l'exception du modificateur de taille qui adapte les contraintes entrantes à la valeur qui lui est transmise.
Figure 8 : Modificateur size ajustant 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 le plus possible aux contraintes transmises tout en respectant les contraintes transmises:

Deux arbres d'UI et leurs représentations correspondantes dans des conteneurs. Dans le premier cas, le modificateur de taille accepte les contraintes entrantes. Dans le second, le modificateur de taille s'adapte aux contraintes trop importantes le plus près possible, ce qui entraîne des contraintes qui remplissent le conteneur.
Figure 9. Le modificateur size respecte la contrainte transmise aussi près que possible.

Notez que l'enchaînement 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 plus petite ou plus grande, il doit toujours respecter les limites exactes transmises. Il ne remplacera donc pas ces valeurs:

Chaîne de deux modificateurs de taille dans l'arborescence de l'UI et sa représentation dans un conteneur, qui est le résultat de la première valeur transmise et non de la deuxième.
Figure 10. Chaîne de deux modificateurs 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 devez remplacer les contraintes entrantes par votre nœud. Le modificateur requiredSize remplace les contraintes entrantes et transmet la taille que vous spécifiez comme limites exactes.

Lorsque la taille est transmise à l'arborescence, le nœud enfant est centré dans l'espace disponible:

Le modificateur de taille et de taille requise en chaîne dans un arbre d'UI, ainsi que la représentation correspondante dans un conteneur. Les contraintes du modificateur requiredSize remplacent les contraintes du modificateur de taille.
Figure 11 Le modificateur requiredSize remplace 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éterminée. De même, avec le modificateur height, vous pouvez définir une hauteur fixe, mais laisser la largeur indéterminée:

Deux arbres d'UI, l'un avec le modificateur de largeur et sa représentation du conteneur, et l'autre avec le modificateur de hauteur et sa représentation.
Figure 12 : Le modificateur width et le modificateur 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'un contrôle précis des contraintes.

Arbre d'interface utilisateur avec le modificateur sizeIn avec des largeurs et hauteurs minimales et maximales définies, et sa représentation dans un conteneur.
Figure 13. Modificateur 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 en chaîne.

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .size(50.dp)
)

Cet extrait génère la sortie suivante:

  • Le modificateur fillMaxSize modifie les contraintes pour définir la largeur et la hauteur minimales sur la valeur maximale (300dp en largeur et 200dp en hauteur).
  • Même si le modificateur size souhaite utiliser une taille de 50dp, il doit respecter les contraintes minimales entrantes. Le modificateur size affichera donc également les limites de contrainte exactes de 300 par 200, ignorant ainsi la valeur fournie dans le modificateur size.
  • Image suit ces limites et indique une taille de 300 par 200, qui est transmise jusqu'en haut de l'arborescence.

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .wrapContentSize()
        .size(50.dp)
)

Cet extrait génère la sortie suivante:

  • Le modificateur fillMaxSize adapte les contraintes pour définir la largeur et la hauteur minimales sur la valeur maximale (300dp en largeur et 200dp en hauteur).
  • Le modificateur wrapContentSize réinitialise les contraintes minimales. Ainsi, alors que fillMaxSize génère des contraintes fixes, wrapContentSize les réinitialise en contraintes limitées. Le nœud suivant peut désormais occuper à nouveau tout l'espace ou être plus petit que l'espace.
  • Le modificateur size définit les contraintes sur les limites minimales et maximales de 50.
  • Image renvoie une taille de 50 par 50, et le modificateur size transmet cela.
  • Le modificateur wrapContentSize possède une propriété spéciale. Il prend son enfant et le place au centre des limites minimales disponibles qui lui ont été transmises. La taille qu'il communique à ses parents est donc égale 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 génère la sortie suivante:

  • Le modificateur clip ne modifie pas les contraintes.
    • Le modificateur padding réduit les contraintes maximales.
    • Le modificateur size définit toutes les contraintes sur 100dp.
    • Image respecte ces contraintes et indique une taille de 100 par 100dp.
    • Le modificateur padding ajoute 10dp à toutes les tailles, ce qui augmente la largeur et la hauteur indiquées de 20dp.
    • Dans la phase de dessin, le modificateur clip agit désormais sur un canevas de 120 par 120dp. Il crée donc un masque circulaire de cette taille.
    • Le modificateur padding insère ensuite son contenu de 10dp pour toutes les tailles, ce qui réduit la taille du canevas à 100 de 100dp.
    • Le Image est dessiné dans ce canevas. L'image est rognée en fonction du cercle d'origine de 120dp. La sortie est donc un résultat non rond.