ConstraintLayout
est une mise en page qui vous permet de positionner des composables par rapport à d'autres composables sur l'écran. Il s'agit d'une alternative à l'utilisation de plusieurs éléments Row
, Column
et Box
imbriqués et d'éléments de mise en page personnalisés. ConstraintLayout
s'avère particulièrement utile pour implémenter des mises en page de grande taille qui présentent des exigences plus complexes en termes d'alignement.
Envisagez d'utiliser ConstraintLayout
dans les scénarios suivants :
- Pour éviter d'imbriquer plusieurs éléments
Column
etRow
afin de positionner des éléments à l'écran et d'améliorer la lisibilité du code - Pour positionner des composables par rapport à d'autres composables ou conformément à des lignes, des barrières ou des chaînes.
Dans le système View, ConstraintLayout
était la méthode recommandée pour créer des mises en page complexes et de grande taille, car une hiérarchie des vues plate était plus performante que les vues imbriquées. Toutefois, cela n'est pas un problème dans Compose qui est capable de gérer efficacement des hiérarchies de mise en page très profondes.
Inscrivez-vous à ConstraintLayout
Pour utiliser ConstraintLayout
dans Compose, vous devez ajouter cette dépendance dans build.gradle
(en plus de la configuration de Compose) :
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1"
Dans Compose, ConstraintLayout
fonctionne de la manière suivante à l'aide d'un DSL :
- Créez des références pour chaque composable dans
ConstraintLayout
à l'aide decreateRefs()
ou decreateRefFor()
. - Les contraintes sont fournies à l'aide du modificateur
constrainAs()
qui utilise la référence comme paramètre et vous permet de spécifier ses contraintes dans le lambda "body". - Les contraintes sont spécifiées à l'aide de
linkTo()
ou d'autres méthodes utiles. parent
est une référence existante qui peut être utilisée pour spécifier des contraintes par rapport au composableConstraintLayout
proprement dit.
Voici un exemple de composable qui utilise ConstraintLayout
:
@Composable fun ConstraintLayoutContent() { ConstraintLayout { // Create references for the composables to constrain val (button, text) = createRefs() Button( onClick = { /* Do something */ }, // Assign reference "button" to the Button composable // and constrain it to the top of the ConstraintLayout modifier = Modifier.constrainAs(button) { top.linkTo(parent.top, margin = 16.dp) } ) { Text("Button") } // Assign reference "text" to the Text composable // and constrain it to the bottom of the Button composable Text( "Text", Modifier.constrainAs(text) { top.linkTo(button.bottom, margin = 16.dp) } ) } }
Ce code contraint le haut du Button
par rapport à l'élément parent avec une marge de 16.dp
et un élément Text
par rapport au bas du Button
, également avec une marge de 16.dp
.
API dissociée
Dans l'exemple ConstraintLayout
, les contraintes sont spécifiées de manière intégrée, avec un modificateur dans le composable auquel elles s'appliquent. Toutefois, il est parfois préférable de dissocier les contraintes des mises en page auxquelles elles s'appliquent. Par exemple, vous pouvez modifier les contraintes en fonction de la configuration de l'écran ou animer deux ensembles de contraintes.
Dans de tels cas, vous pouvez utiliser ConstraintLayout
d'une autre manière :
- Transmettez un
ConstraintSet
en tant que paramètre àConstraintLayout
. - Attribuez des références créées dans le
ConstraintSet
à des composables à l'aide du modificateurlayoutId
.
@Composable fun DecoupledConstraintLayout() { BoxWithConstraints { val constraints = if (minWidth < 600.dp) { decoupledConstraints(margin = 16.dp) // Portrait constraints } else { decoupledConstraints(margin = 32.dp) // Landscape constraints } ConstraintLayout(constraints) { Button( onClick = { /* Do something */ }, modifier = Modifier.layoutId("button") ) { Text("Button") } Text("Text", Modifier.layoutId("text")) } } } private fun decoupledConstraints(margin: Dp): ConstraintSet { return ConstraintSet { val button = createRefFor("button") val text = createRefFor("text") constrain(button) { top.linkTo(parent.top, margin = margin) } constrain(text) { top.linkTo(button.bottom, margin) } } }
Lorsque vous devrez modifier les contraintes, il vous suffira de transmettre un autre élément ConstraintSet
.
Concepts ConstraintLayout
ConstraintLayout
implique des concepts tels que des lignes, des barrières et des chaînes qui peuvent aider à positionner des éléments dans votre composable.
Lignes
Les lignes sont de petits outils visuels permettant de concevoir des mises en page. Les composables peuvent se limiter à une ligne. Les lignes sont utiles pour positionner des éléments à un certain niveau (dp
ou percentage
) dans le composable parent.
Il existe deux types de lignes : verticales et horizontales. Les deux lignes horizontales sont top
et bottom
, et les deux verticales sont start
et end
.
ConstraintLayout { // Create guideline from the start of the parent at 10% the width of the Composable val startGuideline = createGuidelineFromStart(0.1f) // Create guideline from the end of the parent at 10% the width of the Composable val endGuideline = createGuidelineFromEnd(0.1f) // Create guideline from 16 dp from the top of the parent val topGuideline = createGuidelineFromTop(16.dp) // Create guideline from 16 dp from the bottom of the parent val bottomGuideline = createGuidelineFromBottom(16.dp) }
Pour créer une ligne, utilisez createGuidelineFrom*
avec le type approprié. Cette opération crée une référence qui pourra être utilisée dans le bloc Modifier.constrainAs()
.
Barrières
Les barrières référencent plusieurs composables pour créer une ligne virtuelle basée sur le widget le plus extrême du côté spécifié.
Pour créer une barrière, utilisez createTopBarrier()
(ou createBottomBarrier()
, createEndBarrier()
, createStartBarrier()
) et fournissez les références qui doivent la constituer.
ConstraintLayout { val constraintSet = ConstraintSet { val button = createRefFor("button") val text = createRefFor("text") val topBarrier = createTopBarrier(button, text) } }
Vous pourrez ensuite utiliser la barrière dans un bloc Modifier.constrainAs()
.
Chaînes
Les chaînes fournissent un comportement semblable à celui d'un groupe sur un seul axe (horizontal ou vertical). L'autre axe peut être contraint indépendamment.
Pour créer une chaîne, utilisez createVerticalChain
ou createHorizontalChain
:
ConstraintLayout { val constraintSet = ConstraintSet { val button = createRefFor("button") val text = createRefFor("text") val verticalChain = createVerticalChain(button, text, chainStyle = ChainStyle.Spread) val horizontalChain = createHorizontalChain(button, text) } }
La chaîne pourra ensuite être utilisée dans le bloc Modifier.constrainAs()
.
Une chaîne peut être configurée avec différents ChainStyles
, qui déterminent comment gérer l'espace autour d'un composable, par exemple :
ChainStyle.Spread
: l'espace est réparti uniformément entre tous les composables, y compris l'espace libre avant le premier composable et après le dernier.ChainStyle.SpreadInside
: l'espace est réparti uniformément entre tous les composables, sans espace libre avant le premier composable ou après le dernier.ChainStyle.Packed
: l'espace est distribué avant le premier composable et après le dernier. Les composables sont regroupés sans espace pour les séparer.
En savoir plus
Pour en savoir plus sur ConstraintLayout
dans Compose à partir des API en action, consultez la
Exemples de Compose qui utilisent ConstraintLayout
.
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé.
- Sélection dans Compose
- Kotlin pour Jetpack Compose
- Principes de base de la mise en page dans Compose