Una de las reglas de Compose es que solo debes medir tus elementos secundarios una vez. Si lo haces dos veces, se genera una excepción de tiempo de ejecución. Sin embargo, hay momentos en los que necesitas información sobre tus elementos secundarios antes de medirlos.
Los elementos intrínsecos te permiten realizar consultas a los elementos secundarios antes de que se midan realmente.
Para un elemento componible, puedes solicitar su IntrinsicSize.Min
o IntrinsicSize.Max
:
Modifier.width(IntrinsicSize.Min)
: ¿Cuál es el ancho mínimo que necesitas para mostrar tu contenido correctamente?Modifier.width(IntrinsicSize.Max)
: ¿Cuál es el ancho máximo que necesitas para mostrar tu contenido correctamente?Modifier.height(IntrinsicSize.Min)
: ¿Cuál es la altura mínima que necesitas para mostrar tu contenido correctamente?Modifier.height(IntrinsicSize.Max)
: ¿Cuál es la altura máxima que necesitas para mostrar tu contenido correctamente?
Por ejemplo, si solicitas la minIntrinsicHeight
de un Text
con restricciones de width
infinitas en un diseño personalizado, se mostrará la height
del Text
con el texto dibujado en una sola línea.
Funciones intrínsecas en acción
Puedes crear un elemento componible que muestre dos textos en la pantalla separados por un divisor:
Para ello, usa un Row
con dos elementos Text
componibles que llenen el espacio disponible y un Divider
en el medio. El Divider
debe ser tan alto como el Text
más alto y delgado (width = 1.dp
).
@Composable fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) { Row(modifier = modifier) { Text( modifier = Modifier .weight(1f) .padding(start = 4.dp) .wrapContentWidth(Alignment.Start), text = text1 ) VerticalDivider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } }
El elemento Divider
se expande a toda la pantalla, lo que no es el comportamiento deseado:
Esto ocurre porque Row
mide cada elemento secundario de forma individual, y la altura de Text
no se puede usar para restringir Divider
.
Para que el Divider
ocupe el espacio disponible con una altura determinada, usa el modificador height(IntrinsicSize.Min)
.
height(IntrinsicSize.Min)
ajusta el tamaño de sus elementos secundarios para que sean tan altos como su altura mínima intrínseca. Dado que este modificador es recursivo, consulta el minIntrinsicHeight
del Row
y sus elementos secundarios.
Si aplicas este modificador a tu código, funcionará según lo esperado:
@Composable fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) { Row(modifier = modifier.height(IntrinsicSize.Min)) { Text( modifier = Modifier .weight(1f) .padding(start = 4.dp) .wrapContentWidth(Alignment.Start), text = text1 ) VerticalDivider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } } // @Preview @Composable fun TwoTextsPreview() { MaterialTheme { Surface { TwoTexts(text1 = "Hi", text2 = "there") } } }
Con vista previa:
La altura de Row
se determina de la siguiente manera:
- El
minIntrinsicHeight
del elemento componibleRow
es elminIntrinsicHeight
máximo de sus elementos secundarios. - El
minIntrinsicHeight
del elementoDivider
es 0, ya que no ocupa espacio si no se le aplican restricciones. - El
Text
minIntrinsicHeight
es el del texto para unwidth
específico. - Por lo tanto, la restricción
height
del elementoRow
se convierte en laminIntrinsicHeight
máxima de losText
. - Luego,
Divider
expande suheight
a la restricción deheight
proporcionada porRow
.
Funciones intrínsecas en tus diseños personalizados
Cuando se crea un modificador Layout
o layout
personalizado, las mediciones intrínsecas se calculan automáticamente en función de aproximaciones. Por lo tanto, es posible que los cálculos no sean correctos para todos los diseños. Estas APIs ofrecen opciones para anular estos valores predeterminados.
Para especificar las mediciones intrínsecas de tu Layout
personalizado, anula minIntrinsicWidth
, minIntrinsicHeight
, maxIntrinsicWidth
y maxIntrinsicHeight
de la interfaz MeasurePolicy
cuando la crees.
@Composable fun MyCustomComposable( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( content = content, modifier = modifier, measurePolicy = object : MeasurePolicy { override fun MeasureScope.measure( measurables: List<Measurable>, constraints: Constraints ): MeasureResult { // Measure and layout here // ... } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurables: List<IntrinsicMeasurable>, height: Int ): Int { // Logic here // ... } // Other intrinsics related methods have a default value, // you can override only the methods that you need. } ) }
Cuando crees el modificador layout
personalizado, anula los métodos relacionados en la interfaz LayoutModifier
.
fun Modifier.myCustomModifier(/* ... */) = this then object : LayoutModifier { override fun MeasureScope.measure( measurable: Measurable, constraints: Constraints ): MeasureResult { // Measure and layout here // ... } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurable: IntrinsicMeasurable, height: Int ): Int { // Logic here // ... } // Other intrinsics related methods have a default value, // you can override only the methods that you need. }
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Diseños personalizados {:#custom-layouts}
- Líneas de alineación en Jetpack Compose
- Fases de Jetpack Compose