Uma das regras do Compose é que os filhos precisam ser medidos somente uma vez. Medir os filhos duas vezes gera uma exceção de tempo de execução. No entanto, há momentos em que você precisa de algumas informações sobre os filhos antes de medi-los.
Com a medição intrínseca, é possível consultar os elementos filhos antes que eles sejam realmente medidos.
Para uma função de composição, você pode solicitar IntrinsicSize.Min
ou IntrinsicSize.Max
:
Modifier.width(IntrinsicSize.Min)
: qual é a largura mínima necessária para mostrar o conteúdo corretamente?Modifier.width(IntrinsicSize.Max)
: qual é a largura máxima necessária para mostrar o conteúdo corretamente?Modifier.height(IntrinsicSize.Min)
: qual é a altura mínima necessária para mostrar o conteúdo corretamente?Modifier.height(IntrinsicSize.Max)
: qual é a altura máxima necessária para mostrar seu conteúdo corretamente?
Por exemplo, se você solicitar a minIntrinsicHeight
de um Text
com restrições de width
infinitas em um layout personalizado, ela vai retornar a height
do Text
com o texto desenhado em uma única linha.
Medições intrínsecas em ação
Você pode criar um elemento combinável que mostre dois textos na tela separados por um divisor:
Para fazer isso, use um Row
com dois elementos combináveis Text
que preenchem o espaço disponível e um Divider
no meio. O Divider
precisa ter a mesma altura que o
Text
mais alto e ser fino (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 ) } }
O Divider
é expandido para a tela inteira, o que não é o comportamento desejado:
Isso acontece porque Row
mede cada filho individualmente, e a altura de
Text
não pode ser usada para limitar o Divider
.
Para que o Divider
preencha o espaço disponível com uma altura definida, use o modificador height(IntrinsicSize.Min)
.
O height(IntrinsicSize.Min)
dimensiona os filhos para que a altura deles seja igual à altura intrínseca mínima. Como esse modificador é recursivo, ele consulta o
minIntrinsicHeight
do Row
e dos filhos dele.
Aplicar esse modificador ao código faz com que ele funcione como 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") } } }
Com a visualização:
A altura do Row
é determinada da seguinte forma:
- A
minIntrinsicHeight
que pode ser composta daRow
é aminIntrinsicHeight
máxima das filhas dela. - O
minIntrinsicHeight
do elementoDivider
é 0, porque ele não ocupa espaço se nenhuma restrição for definida. - O
Text
minIntrinsicHeight
é o texto de umwidth
específico. - Portanto, a restrição de
height
do elementoRow
se torna aminIntrinsicHeight
máxima dosText
s. - O
Divider
expande aheight
dele para a restrição deheight
especificada peloRow
.
Medições intrínsecas nos layouts personalizados
Ao criar um modificador Layout
ou layout
personalizado, as medições intrínsecas
são calculadas automaticamente com base nas aproximações. Portanto, os
cálculos podem não estar corretos para todos os layouts. Essas APIs oferecem opções
para substituir esses padrões.
Para especificar as medidas intrínsecas do Layout
personalizado, substitua
minIntrinsicWidth
, minIntrinsicHeight
, maxIntrinsicWidth
e
maxIntrinsicHeight
da interface MeasurePolicy
ao criá-la.
@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. } ) }
Ao criar o modificador layout
personalizado, substitua
os métodos relacionados na interface 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. }
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Layouts personalizados {:#custom-layouts}
- Linhas de alinhamento no Jetpack Compose
- Fases do Jetpack Compose