No Compose, os elementos de IU são representados pelas funções que podem ser compostas, que emitem uma parte da IU quando invocadas. Essa parte é, então, adicionadas a uma árvore da IU e renderizada na tela. Cada elemento da IU tem um pai e, possivelmente, muitos filhos. Cada elemento também está localizado no pai, especificado como uma posição (x, y) e um tamanho (width
e height
).
Os pais definem as restrições dos elementos filhos. O tamanho do elemento é definido dentro dessas restrições. As restrições definem os valores mínimo e máximo de width
e height
dos elementos. Caso um elemento tenha elementos filhos, ele poderá medir cada um para ajudar a determinar o tamanho dele. Depois que um elemento determina e informa o próprio tamanho, ele tem a oportunidade de definir o posicionamento dos elementos filhos em relação a ele mesmo, conforme descrito mais detalhadamente em Como criar layouts personalizados.
A disposição de cada nó na árvore da IU é um processo de três etapas. Cada nó precisa:
- medir os filhos;
- decidir o próprio tamanho;
- posicionar os filhos.
O uso de escopos define quando você pode medir e posicionar elementos filhos. A medição de um layout só pode ser feita durante as transmissões de medição e de layout. Um filho só pode ser posicionado durante as transmissões de layout e somente depois de ser medido. Devido aos escopos do Compose, como MeasureScope
e PlacementScope
, isso é aplicado no momento da compilação.
Usar o modificador de layout
É possível usar o modificador layout
para mudar a forma como um elemento é medido e disposto. Layout
é um lambda. Os parâmetros dele incluem o elemento que você pode medir, transmitido como measurable
, e as restrições desse elemento, transmitidas como constraints
. Um modificador de layout personalizado pode ser assim:
fun Modifier.customLayoutModifier() = layout { measurable, constraints -> // ... }
Veja a exibição de um Text
na tela e controle a distância da parte superior até a linha de base da primeira linha do texto. Isso é exatamente o que o modificador paddingFromBaseline
faz, implementado aqui como um exemplo. Para fazer isso, use o modificador layout
para colocar manualmente a função que pode ser composta na tela. Este é o comportamento esperado em que o padding superior do Text
é definido como 24.dp
:
Veja o código que produz esse espaçamento:
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) } }
Confira o que está acontecendo nesse código:
- No parâmetro lamdba
measurable
, oText
representado pelo parâmetro mensurável é medido ao chamarmeasurable.measure(constraints)
. - Para especificar o tamanho do elemento combinável, chame o método
layout(width, height)
, que também fornece um lambda usado para posicionar os elementos agrupados. Nesse caso, ele é a altura entre a última linha de base do texto e o padding superior adicionado. - Posicione os elementos agrupados na tela chamando
placeable.place(x, y)
. Se os elementos agrupados não forem posicionados, eles não ficarão visíveis. A posiçãoy
corresponde ao padding superior, que é a posição da primeira linha de base do texto.
Para verificar se isso funciona como esperado, use este modificador em um 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)) } }
Criar layouts personalizados
O modificador layout
só muda o elemento que é autor da chamada. Para medir e definir o layout de vários elementos combináveis, use o elemento Layout
. Com ele, é possível medir e dispor os filhos manualmente. Todos os layouts de nível superior, como Column
e Row
, são criados com o elemento combinável Layout
.
Vamos criar uma versão muito simples da Column
. A maioria dos layouts personalizados segue este padrão:
@Composable fun MyBasicColumn( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( modifier = modifier, content = content ) { measurables, constraints -> // measure and position children given constraints logic here // ... } }
Assim como o modificador layout
, measurables
é a lista de filhos que precisam ser medidos e constraints
são as restrições do pai. Seguindo a mesma lógica de antes, MyBasicColumn
pode ser implementada da seguinte forma:
@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 } } } }
Os combináveis filhos são limitados pelas restrições de Layout
(sem as de minHeight
) e são posicionados de acordo com a yPosition
do elemento combinável anterior.
Veja como esse elemento personalizado que pode ser composto seria usado:
@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!") } }
Direção do layout
Para mudar a direção do layout de uma função que pode ser composta, mude o local da composição LocalLayoutDirection
.
Quando você posiciona os combináveis manualmente na tela, a LayoutDirection
faz parte do LayoutScope
do modificador layout
ou do combinável Layout
.
Ao usar layoutDirection
, posicione os elementos que podem ser compostos usando place
. Ao contrário do método placeRelative
place
não muda de acordo com a direção do layout (esquerda para a direita ou direita para a esquerda).
Layouts personalizados em ação
Saiba mais sobre layouts e modificadores em Layouts básicos no Compose e veja layouts personalizados em ação nos exemplos do Compose que criam layouts personalizados (link em inglês).
Saiba mais
Para saber mais sobre layouts personalizados no Compose, consulte os recursos abaixo.
Vídeos
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Medições intrínsecas em layouts do Compose
- Gráficos no Compose
- Modificadores do Compose