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 tempo de compilação.
Usar o modificador de layout
É possível usar o modificador layout para mudar a forma como um elemento é medido e
disposto. O modificador usa uma lambda. Os parâmetros incluem o elemento que você pode
medir, transmitido como measurable, e as restrições de entrada do elemento combinável,
transmitidas como constraints. Um modificador de layout personalizado pode ser assim:
fun Modifier.customLayoutModifier() = layout { measurable, constraints -> // ... }
Mostre um Text na tela e controle a distância entre a parte de cima e
a primeira linha de base do texto. Isso é exatamente o que o modificador
paddingFromBaseline faz. Você o está implementando 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 resultante em que o padding superior de Text é definido como 24.dp:
paddingFromBaseline aplicado.
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, oTextrepresentado 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, a altura é a altura doTextmaisplaceableY, que éfirstBaselineToTopmenos a primeira linha de base doText. - Posicione os elementos agrupados na tela chamando
placeable.placeRelative(x, y). Se os elementos encapsulados não forem posicionados, eles não ficarão visíveis. Em um layout da direita para a esquerda,placeRelativeespelha a posição dex. Consulte Direção do layout. A posiçãoyéfirstBaselineToTopmenos a primeira linha de base do texto, de modo que a primeira linha de base sejafirstBaselineToTopda parte de cima.
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)) } }
Text e visualizado.
Criar layouts personalizados
O modificador layout só muda o elemento que é autor da chamada. Para medir e organizar
vários elementos, use o elemento de composição Layout. Esse elemento combinável
permite medir e organizar os filhos manualmente. Todos os layouts de nível mais elevado,
como Column e Row, são criados com o elemento combinável Layout.
Este exemplo cria uma versão muito básica de 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 recebidas 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!") } }
Column.
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.
Se você posicionar os combináveis manualmente na tela, a LayoutDirection vai estar
disponível na propriedade layoutDirection do MeasureScope no
modificador layout ou no 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
- Elementos gráficos no Compose
- Modificadores do Compose