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, use o elemento combinável 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.
- Medidas intrínsecas em layouts do Compose
- Gráficos no Compose
- Modificadores do Compose