ConstraintLayout
puede ayudar a posicionar elementos componibles en relación con otros en la pantalla y es una alternativa al uso de varios Row
, Column
, Box
anidados y diseños personalizados. ConstraintLayout
resulta útil cuando se implementan diseños más grandes con requisitos de alineación más complejos.
Para usar ConstraintLayout
en Compose, debes agregar esta dependencia en tu build.gradle
:
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-beta02"
En Compose, ConstraintLayout
funciona con una DSL:
- Las referencias se crean con
createRefs()
ocreateRefFor()
, y cada elemento componible enConstraintLayout
debe tener una referencia asociada. - Las restricciones se proporcionan mediante el modificador
constrainAs()
, que toma la referencia como parámetro y te permite especificar sus restricciones en la expresión lambda del cuerpo. - Las restricciones se especifican mediante
linkTo()
o algún otro método útil. parent
es una referencia existente que se puede usar para especificar restricciones hacia el mismo elementoConstraintLayout
.
En este ejemplo vemos uno de esos elementos que usa un 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)
})
}
}
Este código restringe la parte superior del Button
al elemento principal, con un margen de 16.dp
, y un Text
a la parte inferior del Button
, también con un margen de 16.dp
.
API desacoplada
En el ejemplo de ConstraintLayout
, las restricciones se especifican de forma intercalada, con un modificador en el elemento que admite composición al que se aplican. Sin embargo, hay situaciones en las que es preferible desacoplar las restricciones de los diseños a los que se aplican. Por ejemplo, quizás querrías cambiar las restricciones en función de la configuración de la pantalla o agregar una animación entre dos conjuntos de restricciones.
En casos como esos, puedes usar ConstraintLayout
de otro modo:
- Pasa un
ConstraintSet
como parámetro aConstraintLayout
. - Asigna referencias creadas en el
ConstraintSet
a los elementos que admiten composición con el modificadorlayoutId
.
@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)
}
}
}
Luego, cuando necesites cambiar las restricciones, simplemente puedes pasar un ConstraintSet
diferente.
Más información
Obtén más información sobre ConstraintLayout en Compose a partir del funcionamiento de las APIs en los ejemplos de Compose que usan ConstraintLayout
.