Contraintes et ordre des modificateurs

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 les 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 positionnement des composables.

Modificateurs dans l'arborescence de l'interface utilisateur

Pour comprendre comment les modificateurs s'influencent mutuellement, il est utile de visualiser comment ils apparaissent dans l'arborescence de l'interface utilisateur, générée pendant la phase de composition. Pour en savoir plus, consultez la section Composition.

Dans l'arborescence de l'interface utilisateur, 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 forme d'arborescence d'interface utilisateur
Figure 1. Modificateurs encapsulant les nœuds de mise en page dans l'arborescence de l'interface utilisateur.

L'ajout de plusieurs modificateurs à un composable crée une chaîne de modificateurs. Lorsque vous associez 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 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.

Au cours 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 façon, 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 elle-même 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 mettre en page leurs enfants.

L'arborescence précédente, qui n'est désormais qu'une simple mise en page, avec de nombreux nœuds modificateurs qui l'entourent.
Figure 2 : Même arborescence que dans la figure 1, mais avec des composables dans l'arborescence de l'interface utilisateur visualisés sous la forme de chaînes de modificateurs.

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 l'enchaînement 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 et la hauteur de chaque nœud de mise en page, ainsi que les coordonnées x et y:

  1. Mesurer les enfants: un nœud mesure ses enfants, le cas échéant.
  2. Décider sa propre taille: en fonction de ces mesures, un nœud décide de sa propre taille.
  3. Placer les enfants: chaque nœud enfant est placé par rapport à la position d'un nœud.

Constraints permet de trouver les tailles de nœuds appropriées lors des deux premières étapes de l'algorithme. Les contraintes définissent les limites minimale et maximale de la largeur et de la 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és: le nœud a une largeur et une hauteur maximales et minimales.
Contraintes limitées de différentes tailles dans un conteneur.
Figure 3. Contraintes limitées
  • Illimité: le nœud n'est limité à aucune taille. Les limites maximales de largeur et de hauteur 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.
  • Exacte: le nœud doit respecter une exigence exacte de taille. Les limites minimale et maximale sont définies sur la même valeur.
Contraintes exactes conformes à 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 affichant des combinaisons de contraintes limitées et illimitées, et des largeurs et des hauteurs exactes.
Figure 6. Combinaisons de contraintes limitées et illimitées, et 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-elles transmises du parent à l'enfant ?

Au cours de la première étape de l'algorithme décrit dans la section Contraintes 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 lui indiquer la taille autorisée ou la taille autorisée. Ensuite, lorsqu'il détermine sa propre taille, il respecte également les contraintes transmises par ses propres parents.

De manière générale, l'algorithme fonctionne de la manière suivante:

  1. Pour déterminer la taille qu'il souhaite occuper, le nœud racine de l'arborescence de l'interface utilisateur 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 les mesures, il transmet les contraintes au modificateur suivant. Les contraintes sont transmises telles quelles dans la chaîne de modificateurs, sauf si un modificateur ayant une incidence sur les mesures est atteint. Les contraintes sont ensuite redimensionnées en conséquence.
  3. Lorsqu'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 sont mesurés, le nœud parent choisit sa propre taille et communique celle-ci à son propre parent.
  6. De cette façon, toute l'arborescence est balayée d'abord en profondeur. À terme, tous les nœuds ont décidé de leur taille et l'étape de mesure est terminée.

Pour un exemple détaillé, regardez la vidéo Contraintes et ordre des modificateurs.

Modificateurs ayant une incidence sur les contraintes

Dans la section précédente, vous avez appris que certains modificateurs peuvent affecter la taille de la contrainte. Les sections suivantes décrivent des modificateurs spécifiques ayant un impact sur les contraintes.

Modificateur size

Le modificateur size déclare la taille souhaitée du contenu.

Par exemple, l'arborescence d'interface utilisateur suivante doit s'afficher dans un conteneur de 300dp par 200dp. Les contraintes sont limitées, ce qui permet d'utiliser des largeurs comprises entre 100dp et 300dp, et des hauteurs entre 100dp et 200dp:

Partie d'une arborescence d'interface utilisateur avec le modificateur de taille encapsulant un nœud de mise en page, ainsi que 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'interface utilisateur et sa 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:

Comme sur la figure 7, la différence est que le modificateur de taille adapte les contraintes entrantes pour qu'elles correspondent à la valeur qui lui est transmise.
Figure 8 : Le modificateur size ajuste les contraintes sur 150dp.

Si la largeur et la hauteur sont inférieures à la plus petite limite de contrainte ou supérieures à la limite la plus élevée, le modificateur établit une correspondance aussi fidèle que possible avec les contraintes transmises, tout en respectant les contraintes transmises:

Deux arborescences d'interface utilisateur et leurs représentations correspondantes dans des conteneurs Dans la première, le modificateur de taille accepte les contraintes croissantes. Dans la seconde, il s'adapte le plus près possible aux contraintes trop grandes, ce qui génère des contraintes qui remplissent le conteneur.
Figure 9. Modificateur size respectant le plus possible la contrainte transmise.

Notez que l'association de plusieurs modificateurs size ne fonctionne pas. Le premier modificateur size définit les contraintes minimales et maximales 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. Il ne remplace donc 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é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 (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 renvoyée vers le haut de l'arborescence, le nœud enfant est centré dans l'espace disponible:

Le modificateur de taille et de modificateur requiredSize enchaîné dans une arborescence d'interface utilisateur, et la représentation correspondante dans un conteneur. Les contraintes du modificateur requiredSize remplacent les contraintes du modificateur de taille.
Figure 11 : Le modificateur requiredSize remplaçant 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 ne pas déterminer la hauteur. De même, avec le modificateur height, vous pouvez définir une hauteur fixe, mais ne pas définir la largeur:

Deux arborescences d'interface utilisateur, l'une avec le modificateur de largeur et sa représentation de conteneur, et l'autre avec le modificateur de hauteur et sa représentation.
Figure 12 : Les modificateurs 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'interface utilisateur avec le modificateur sizeIn, avec des largeurs et des hauteurs minimales et maximales définies, ainsi que sa représentation dans un conteneur.
Figure 13. Modificateur sizeIn avec minWidth, maxWidth, minHeight et maxHeight définis.

Exemples

Cette section montre et explique la sortie 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 produit le résultat suivant:

  • 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 tout de même respecter les contraintes minimales entrantes. Par conséquent, le modificateur size affiche également les limites exactes de 300 par 200, en ignorant la valeur fournie dans le modificateur size.
  • Image suit ces limites et signale une taille de 300 par 200, qui est transmise tout au long de l'arborescence.

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

Cet extrait produit le résultat suivant:

  • 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érait des contraintes fixes, wrapContentSize réinitialise les contraintes limitées. Le nœud suivant peut maintenant occuper à nouveau la totalité de l'espace ou être plus petit que l'espace entier.
  • Le modificateur size définit les contraintes sur les limites minimale et maximale de 50.
  • Image résout une taille de 50 par 50, et le modificateur size la transfère.
  • Le modificateur wrapContentSize possède une propriété spéciale. Elle 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 y 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 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 sur 100dp.
    • Le Image respecte ces contraintes et indique une taille de 100 par 100dp.
    • Le modificateur padding ajoute 10dp sur toutes les tailles, ce qui augmente de 20dp la largeur et la hauteur rapportées.
    • Maintenant, dans la phase de dessin, le modificateur clip agit sur un canevas de 120 par 120dp. Donc, cela crée un masque circulaire de cette taille.
    • Le modificateur padding insère ensuite son contenu par 10dp sur toutes les tailles, de sorte qu'il réduit la taille du canevas à 100 de 100dp.
    • 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 arrondi.