Les modificateurs vous permettent d'apporter des éléments décoratifs ou d'améliorer un composable. Ils permettent par exemple d'effectuer les opérations suivantes :
- Modifier la taille, la mise en page, le comportement et l'apparence du composable
- Ajouter des informations, comme des libellés d'accessibilité
- Traiter les entrées utilisateur
- Ajouter des interactions de haut niveau (par exemple, faire en sorte que l'utilisateur puisse cliquer sur un élément, le faire défiler, le déplacer ou zoomer dessus)
Les modificateurs sont des objets Kotlin standards. Pour créer un modificateur, appelez l'une des fonctions de la classe Modifier
:
@Composable private fun Greeting(name: String) { Column(modifier = Modifier.padding(24.dp)) { Text(text = "Hello,") Text(text = name) } }
Vous pouvez associer ces fonctions pour les composer :
@Composable private fun Greeting(name: String) { Column( modifier = Modifier .padding(24.dp) .fillMaxWidth() ) { Text(text = "Hello,") Text(text = name) } }
Dans le code ci-dessus, vous remarquerez que plusieurs fonctions sont utilisées.
padding
ajoute de l'espace autour d'un élément.fillMaxWidth
fait en sorte que le composable remplisse la largeur maximale qui lui est attribuée par son parent.
Il est recommandé de faire en sorte que tous vos composables acceptent un paramètre modifier
et transmettent ce modificateur à son premier enfant qui émet l'interface utilisateur.
Cela permet de réutiliser votre code plus facilement, et rend son comportement plus prévisible et intuitif. Pour en savoir plus, consultez les consignes relatives aux API de Compose, en particulier Éléments acceptant et suivant un paramètre modificateur.
L'ordre des modificateurs a de l'importance
L'ordre des fonctions de modificateur joue un rôle majeur. Étant donné que chaque fonction modifie le Modifier
renvoyé par la fonction précédente, la séquence a une incidence sur le résultat final. Prenons un exemple :
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { // rest of the implementation } }
Dans le code ci-dessus, toute la zone est cliquable, y compris la marge intérieure tout autour de l'élément, car le modificateur padding
a été appliqué après le modificateur clickable
. Si l'ordre des modificateurs est inversé, l'espace ajouté par padding
ne réagit pas aux entrées utilisateur :
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .padding(padding) .clickable(onClick = onClick) .fillMaxWidth() ) { // rest of the implementation } }
Modificateurs intégrés
Jetpack Compose propose plusieurs modificateurs intégrés pour vous aider à améliorer un composable ou à lui ajouter des éléments décoratifs. Voici quelques modificateurs communément utilisés pour ajuster des mises en page.
padding
et size
Par défaut, les mises en page fournies dans Compose encapsulent les enfants. Toutefois, vous pouvez définir une taille à l'aide du modificateur size
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image(/*...*/) Column { /*...*/ } } }
Notez que la taille que vous avez spécifiée peut ne pas être respectée si elle ne répond pas aux contraintes provenant du parent de la mise en page. Si vous souhaitez que la taille du composable soit appliquée quelles que soient les contraintes entrantes, utilisez le modificateur requiredSize
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.requiredSize(150.dp) ) Column { /*...*/ } } }
Dans cet exemple, même avec la height
du parent définie sur 100.dp
, la hauteur de l'Image
sera 150.dp
, car le modificateur requiredSize
prévaut.
Si vous souhaitez qu'une mise en page enfant remplisse toute la hauteur disponible autorisée par le parent, ajoutez le modificateur fillMaxHeight
(Compose fournit également fillMaxSize
et fillMaxWidth
) :
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.fillMaxHeight() ) Column { /*...*/ } } }
Pour ajouter une marge intérieure tout autour d'un élément, définissez un modificateur padding
.
Si vous souhaitez ajouter une marge intérieure au-dessus d'une ligne de base d'un texte afin d'atteindre une distance spécifique avec lehaut de la mise en page, utilisez le modificateur paddingFromBaseline
:
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text( text = artist.name, modifier = Modifier.paddingFromBaseline(top = 50.dp) ) Text(artist.lastSeenOnline) } } }
Décalage
Pour positionner une mise en page par rapport à sa position d'origine, ajoutez le modificateur offset
et définissez le décalage sur les axes x et y.
Les décalages peuvent être positifs ou non. La différence entre padding
et offset
est que l'ajout d'un offset
à un composable ne modifie pas ses mesures:
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text(artist.name) Text( text = artist.lastSeenOnline, modifier = Modifier.offset(x = 4.dp) ) } } }
Le modificateur offset
est appliqué horizontalement en fonction de la direction de la mise en page.
Dans un contexte d'affichage de gauche à droite, un offset
positif déplace l'élément vers la droite, tandis que dans un contexte d'affichage droite à gauche, il déplace l'élément vers la gauche.
Si vous devez définir un décalage sans tenir compte de la direction de la mise en page, consultez le modificateur absoluteOffset
, pour lequel une valeur de décalage positive déplace toujours l'élément vers la droite.
Le modificateur offset
fournit deux surcharges : offset
, qui utilise les décalages comme paramètres, et offset
, qui accepte un lambda.
Pour en savoir plus sur l'utilisation de chacun de ces paramètres et sur la façon d'optimiser les performances, consultez la section Performances de Compose - Reporter les lectures le plus longtemps possible.
Sûreté des champs d'application dans Compose
Dans Compose, il existe des modificateurs qui ne sont utilisables que lorsqu'ils sont appliqués aux enfants de certains composables. Compose applique ces modificateurs par le biais de champs d'application personnalisés.
Par exemple, si vous souhaitez rendre un enfant aussi grand que le Box
parent sans affecter la taille du Box
, utilisez le modificateur matchParentSize
. matchParentSize
n'est disponible que dans BoxScope
.
Par conséquent, il ne peut être utilisé que sur un enfant dans un parent Box
.
La sûreté des champs d'application vous évite d'ajouter des modificateurs qui ne fonctionneraient pas dans d'autres composables et champs d'application, et vous fait gagner du temps en cas d'erreur lors de tests.
Les modificateurs avec champ d'application transmettent au parent certaines informations qu'il doit connaître sur l'enfant. On les appelle également des modificateurs de données parents. Leur fonctionnement interne est différent des modificateurs à usage général, mais du point de vue de l'utilisation, cela n'a pas d'importance.
matchParentSize
en Box
Comme indiqué ci-dessus, si vous souhaitez qu'une mise en page enfant ait la même taille qu'un conteneur Box
parent sans affecter la taille ce celui-ci, utilisez le modificateur matchParentSize
.
Notez que matchParentSize
n'est disponible que dans le champ d'application Box
, ce qui signifie qu'il ne s'applique qu'aux enfants directs de composables Box
.
Dans l'exemple ci-dessous, l'élément enfant Spacer
tire sa taille de son parent Box
, qui tire lui-même ses dimensions des enfants de plus grande taille, ArtistCard
dans ce cas.
@Composable fun MatchParentSizeComposable() { Box { Spacer( Modifier .matchParentSize() .background(Color.LightGray) ) ArtistCard() } }
Si fillMaxSize
est utilisé à la place de matchParentSize
, Spacer
occupe alors tout l'espace disponible pour le parent, ce qui entraîne l'expansion du parent et le remplissage de l'espace disponible.
weight
dans Row
et Column
Comme vous avez pu le constater dans la section précédente (Marge intérieure et taille), par défaut, la taille d'un composable est définie par le contenu qu'il encapsule. Vous pouvez définir la taille d'un composable pour qu'elle soit flexible dans les limites de son élément parent à l'aide du modificateur weight
, qui n'est disponible que pour RowScope
et ColumnScope
.
Prenons un élément Row
contenant deux composables Box
.
Le premier conteneur reçoit une valeur weight
qui représente le double du second. Sa largeur est donc deux fois plus importante. Étant donné que la Row
fait 210.dp
de large, le premier Box
fait 140.dp
de large et le second 70.dp
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.fillMaxWidth() ) { Image( /*...*/ modifier = Modifier.weight(2f) ) Column( modifier = Modifier.weight(1f) ) { /*...*/ } } }
Extraire et réutiliser des modificateurs
Plusieurs modificateurs peuvent être enchaînés pour décorer ou enrichir un composable. Cette chaîne est créée via l'interface Modifier
qui représente une liste ordonnée et immuable de Modifier.Elements
uniques.
Chaque Modifier.Element
représente un comportement individuel, comme les comportements de mise en page, de dessin et de graphique, tous les comportements liés aux gestes, à la mise au point et à la sémantique, ainsi que les événements de saisie de l'appareil. Leur ordre est important : les éléments modificateurs ajoutés en premier seront appliqués en premier.
Parfois, il peut être utile de réutiliser les mêmes instances de chaîne de modificateur dans plusieurs composables, en les extrayant dans des variables et en les hissant dans des champs d'application plus élevés. Cela peut améliorer la lisibilité du code ou les performances de votre application pour plusieurs raisons :
- La réallocation des modificateurs n'est pas répétée lors de la recomposition des composables qui les utilisent.
- Les chaînes de modificateur peuvent être très longues et complexes. Réutiliser la même instance d'une chaîne peut donc réduire la charge de travail de l'environnement d'exécution Compose lorsqu'il doit les comparer.
- Cette extraction favorise la propreté, la cohérence et la facilité de gestion du code dans le codebase.
Bonnes pratiques concernant la réutilisation des modificateurs
Créez vos propres chaînes Modifier
et extrayez-les pour les réutiliser sur plusieurs composants composables. Il est parfaitement acceptable de simplement enregistrer des modificateurs, car il s'agit d'objets semblables à des données :
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
Extraire et réutiliser des modificateurs lors de l'observation d'états changeant fréquemment
Lorsque vous observez des états qui changent fréquemment dans des composables, comme des états d'animation ou scrollState
, un grand nombre de recompositions peut être effectué. Dans ce cas, vos modificateurs sont alloués à chaque recomposition et potentiellement à chaque frame :
@Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // Creation and allocation of this modifier will happen on every frame of the animation! modifier = Modifier .padding(12.dp) .background(Color.Gray), animatedState = animatedState ) }
Au lieu de cela, vous pouvez créer, extraire et réutiliser la même instance du modificateur, et la transmettre au composable comme suit :
// Now, the allocation of the modifier happens here: val reusableModifier = Modifier .padding(12.dp) .background(Color.Gray) @Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // No allocation, as we're just reusing the same instance modifier = reusableModifier, animatedState = animatedState ) }
Extraire et réutiliser des modificateurs sans champ d'application
Les modificateurs peuvent être étendus ou limités à un composable spécifique. Dans le cas des modificateurs sans champ d'application, vous pouvez facilement les extraire en dehors de tout composable en tant que variables simples :
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) @Composable fun AuthorField() { HeaderText( // ... modifier = reusableModifier ) SubtitleText( // ... modifier = reusableModifier ) }
Cela peut s'avérer particulièrement utile en cas de combinaison avec des mises en page différées. Dans la plupart des cas, il est préférable que tous vos éléments (qui peuvent être nombreux) présentent exactement les mêmes modificateurs :
val reusableItemModifier = Modifier .padding(bottom = 12.dp) .size(216.dp) .clip(CircleShape) @Composable private fun AuthorList(authors: List<Author>) { LazyColumn { items(authors) { AsyncImage( // ... modifier = reusableItemModifier, ) } } }
Extraire et réutiliser des modificateurs avec champ d'application
Lorsque vous traitez des modificateurs limités à certains composables, vous pouvez les extraire au niveau le plus élevé possible et les réutiliser le cas échéant :
Column(/*...*/) { val reusableItemModifier = Modifier .padding(bottom = 12.dp) // Align Modifier.Element requires a ColumnScope .align(Alignment.CenterHorizontally) .weight(1f) Text1( modifier = reusableItemModifier, // ... ) Text2( modifier = reusableItemModifier // ... ) // ... }
Vous ne devez transmettre les modificateurs avec champ d'application extraits qu'aux enfants directs du même champ. Pour en savoir plus sur l'importance de cette opération, consultez la section Sûreté des champs d'application dans Compose.
Column(modifier = Modifier.fillMaxWidth()) { // Weight modifier is scoped to the Column composable val reusableItemModifier = Modifier.weight(1f) // Weight will be properly assigned here since this Text is a direct child of Column Text1( modifier = reusableItemModifier // ... ) Box { Text2( // Weight won't do anything here since the Text composable is not a direct child of Column modifier = reusableItemModifier // ... ) } }
Chaînage supplémentaire des modificateurs extraits
Vous pouvez enchaîner ou ajouter vos chaînes de modificateur extraites en appelant la fonction .then()
:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) // Append to your reusableModifier reusableModifier.clickable { /*...*/ } // Append your reusableModifier otherModifier.then(reusableModifier)
Gardez simplement à l'esprit que l'ordre des modificateurs est important.
En savoir plus
N'hésitez pas à consulter la liste complète des modificateurs, avec leurs paramètres et champs d'application.
Pour vous entraîner davantage à utiliser des modificateurs, vous pouvez également suivre l'atelier de programmation Mises en page de base dans Compose ou consulter le dépôt Now in Android.
Pour en savoir plus sur les modificateurs personnalisés et leur création, consultez la documentation Mises en page personnalisées - Utiliser le modificateur de mise en page.
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé.
- Principes de base de la mise en page dans Compose
- Actions de l'éditeur {:#editor-actions}
- Mises en page personnalisées {:#custom-layouts }