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
minIntrinsicHeightdel elemento componibleRowes elminIntrinsicHeightmáximo de sus elementos secundarios. - El
minIntrinsicHeightdel elementoDivideres 0, ya que no ocupa espacio si no se le aplican restricciones. - El
TextminIntrinsicHeightes el del texto para unwidthespecífico. - Por lo tanto, la restricción
heightdel elementoRowse convierte en laminIntrinsicHeightmáxima de losText. - Luego,
Dividerexpande suheighta la restricción deheightproporcionada 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