En Compose, los elementos de la IU se representan con funciones que admiten composición y que emiten una porción de la IU cuando se invoca, que luego se agregan a un árbol de IU que se procesa en la pantalla. Cada elemento de la IU tiene un elemento superior y, posiblemente, varios secundarios. Cada elemento también está ubicado dentro de su elemento superior, especificado como una posición (x, y) y un tamaño, especificado como width
y height
.
Los elementos superiores definen las restricciones de sus elementos secundarios. Se solicita a un elemento que defina su tamaño dentro de esas restricciones. Las restricciones limitan los valores mínimos y máximos de width
y height
de un elemento. Si un elemento tiene elementos secundarios, puede medir cada uno de ellos para ayudar a determinar su tamaño. Una vez que un elemento determina e informa su propio tamaño, tiene la oportunidad de definir cómo colocar sus elementos secundarios en relación con ellos, según se describe en detalle en Cómo crear diseños personalizados.
El diseño de cada nodo en el árbol de IU es un proceso de tres pasos. Cada nodo debe:
- Medir todos los elementos secundarios
- Decidir su propio tamaño
- Ubicar a los elementos secundarios
El uso de alcances define cuándo puedes medir y ubicar tus elementos secundarios.
Solo podrás medir un diseño mientras se realicen los pases de medición y diseño. Podrás ubicar un elemento secundario únicamente durante los pases de diseño (y solo después de que se haya medido de antemano). Debido a los alcances de Compose, como MeasureScope
y PlacementScope
, esto se aplica de manera forzosa en el tiempo de compilación.
Cómo usar el modificador de diseño
Puedes usar el modificador layout
para modificar la forma en que se mide y se organiza un elemento. Layout
es una expresión lambda; sus parámetros incluyen el elemento componible que puedes medir, que se pasó como measurable
, y las restricciones correspondientes a ese elemento, que se pasaron como constraints
. Un modificador de diseño personalizado puede verse de la siguiente manera:
fun Modifier.customLayoutModifier() = layout { measurable, constraints -> // ... }
Mostremos un Text
en la pantalla y controlemos la distancia desde la parte superior hasta la línea de base de la primera línea de texto. Esto es exactamente lo que hace el modificador paddingFromBaseline
. Lo estamos implementando aquí como un ejemplo.
Para ello, usa el modificador layout
, que permite colocar el elemento componible de forma manual en la pantalla. Este es el comportamiento deseado en el que el padding superior de Text
está configurado en 24.dp
:
Este es el código que genera ese espaciado:
fun Modifier.firstBaselineToTop( firstBaselineToTop: Dp ) = layout { measurable, constraints -> // Measure the composable val placeable = measurable.measure(constraints) // Check the composable has a first baseline check(placeable[FirstBaseline] != AlignmentLine.Unspecified) val firstBaseline = placeable[FirstBaseline] // Height of the composable with padding - first baseline val placeableY = firstBaselineToTop.roundToPx() - firstBaseline val height = placeable.height + placeableY layout(placeable.width, height) { // Where the composable gets placed placeable.placeRelative(0, placeableY) } }
Esto es lo que sucede en este código:
- En el parámetro lambda
measurable
, puedes medir elText
representado por el parámetro medible llamando ameasurable.measure(constraints)
. - A fin de especificar el tamaño del elemento componible, llama al método
layout(width, height)
, que también proporciona una expresión lambda que se usa para posicionar los elementos secundarios. En este caso, es la altura entre la última línea de base y el padding superior agregado. - Para posicionar los elementos unidos en la pantalla, llama a
placeable.place(x, y)
. Si no se colocan los elementos unidos, no serán visibles. La posicióny
corresponde al padding superior, es decir, la posición de la primera línea de base del texto.
Para verificar que funcione como se espera, usa este modificador sobre un Text
:
@Preview @Composable fun TextWithPaddingToBaselinePreview() { MyApplicationTheme { Text("Hi there!", Modifier.firstBaselineToTop(32.dp)) } } @Preview @Composable fun TextWithNormalPaddingPreview() { MyApplicationTheme { Text("Hi there!", Modifier.padding(top = 32.dp)) } }
Cómo crear diseños personalizados
El modificador layout
solo cambia el elemento componible al que se llama. Para medir y diseñar varios elementos componibles, usa el elemento Layout
. Ese elemento te permite medir e implementar elementos secundarios de forma manual. Todos los diseños de nivel superior, como Column
y Row
, se compilan con el elemento componible Layout
.
Compilemos una versión muy básica de Column
. La mayoría de los diseños personalizados siguen este patrón:
@Composable fun MyBasicColumn( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( modifier = modifier, content = content ) { measurables, constraints -> // measure and position children given constraints logic here // ... } }
Al igual que el modificador layout
, measurables
es la lista de elementos secundarios que deben medirse, y constraints
son las restricciones del elemento superior.
Siguiendo la misma lógica de antes, se puede implementar MyBasicColumn
de la siguiente manera:
@Composable fun MyBasicColumn( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( modifier = modifier, content = content ) { measurables, constraints -> // Don't constrain child views further, measure them with given constraints // List of measured children val placeables = measurables.map { measurable -> // Measure each children measurable.measure(constraints) } // Set the size of the layout as big as it can layout(constraints.maxWidth, constraints.maxHeight) { // Track the y co-ord we have placed children up to var yPosition = 0 // Place children in the parent layout placeables.forEach { placeable -> // Position item on the screen placeable.placeRelative(x = 0, y = yPosition) // Record the y co-ord placed up to yPosition += placeable.height } } } }
Los elementos componibles secundarios están limitados por las restricciones Layout
(sin las restricciones minHeight
) y se colocan según la yPosition
del elemento componible anterior.
Así es cómo se usaría ese elemento personalizado:
@Composable fun CallingComposable(modifier: Modifier = Modifier) { MyBasicColumn(modifier.padding(8.dp)) { Text("MyBasicColumn") Text("places items") Text("vertically.") Text("We've done it by hand!") } }
Dirección del diseño
Para cambiar la dirección del diseño de un elemento componible, cambia el objeto de composition local LocalLayoutDirection
.
Si quieres posicionar elementos componibles de manera manual en la pantalla, la LayoutDirection
forma parte del LayoutScope
del modificador layout
o del elemento Layout
.
Cuando uses layoutDirection
, posiciona los elementos que admiten composición con place
. A diferencia del método placeRelative
, place
no cambia en función de la dirección de lectura (de izquierda a derecha o de derecha a izquierda).
Diseños personalizados en acción
Obtén más información sobre los diseños y los modificadores en el documento sobre diseños básicos en Compose y consulta los diseños personalizados en acción en los ejemplos de Compose para crear diseños personalizados.
Más información
Si deseas obtener más información sobre diseños personalizados en Compose, consulta los siguientes recursos adicionales.
Videos
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Mediciones intrínsecas en los diseños de Compose
- Gráficos en Compose
- Modificadores de Compose