O modelo de layout do Compose possibilita o uso da AlignmentLine
para criar linhas
de alinhamento personalizadas que podem ser usadas por layouts pais para alinhar e posicionar os
filhos. Por exemplo,
a Row
pode usar as linhas de alinhamento personalizadas dos filhos para alinhá-los.
Quando um layout fornece um valor para uma determinada AlignmentLine
, os pais
do layout podem ler esse valor após a medição, usando o operador Placeable.get
na instância do
Placeable
correspondente.
Com base na posição da AlignmentLine
, os pais podem
decidir o posicionamento dos filhos.
Alguns elementos que podem ser compostos no Compose já vêm com linhas de alinhamento. Por exemplo, o
BasicText
de composição expõe as linhas de alinhamento FirstBaseline
e LastBaseline
.
No exemplo abaixo, um LayoutModifier
personalizado chamado
firstBaselineToTop
lê a FirstBaseline
para adicionar padding ao Text
começando pela primeira linha de base.
Figura 1. Mostra a diferença entre adicionar padding normal a um elemento e aplicar padding à linha de base de um elemento de texto.
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) } } @Preview @Composable private fun TextWithPaddingToBaseline() { MaterialTheme { Text("Hi there!", Modifier.firstBaselineToTop(32.dp)) } }
Para ler a FirstBaseline
no exemplo,
placeable [FirstBaseline]
é usado na fase de medição.
Criar linhas de alinhamento personalizadas
Ao criar um Layout
combináveis
ou um LayoutModifier
personalizado, você pode fornecer
linhas de alinhamento personalizadas para que outros elementos combináveis pai possam usá-las para alinhar
e posicionar os filhos adequadamente.
O exemplo a seguir mostra um BarChart
combináveis personalizado que expõe duas
linhas de alinhamento, MaxChartValue
e MinChartValue
, para que outros elementos combináveis
se alinhem aos valores máximo e mínimo dos dados do gráfico. Dois elementos
de texto, Max e Min, foram alinhados com o centro das linhas de alinhamento
personalizadas.
Figura 2. BarChart
que pode ser composto com texto alinhado ao valor máximo e
mínimo dos dados.
As linhas de alinhamento personalizadas são definidas como variáveis de nível superior no seu projeto.
/** * AlignmentLine defined by the maximum data value in a [BarChart] */ private val MaxChartValue = HorizontalAlignmentLine(merger = { old, new -> min(old, new) }) /** * AlignmentLine defined by the minimum data value in a [BarChart] */ private val MinChartValue = HorizontalAlignmentLine(merger = { old, new -> max(old, new) })
As linhas de alinhamento personalizadas para criar nosso exemplo são do tipo
HorizontalAlignmentLine
, porque
são usadas para alinhar filhos verticalmente. Uma política de combinação é transmitida como um
parâmetro quando vários layouts fornecem um valor para essas linhas de alinhamento. Como
as coordenadas do sistema de layout do Compose e as coordenadas Canvas
representam [0, 0]
, o canto superior esquerdo e os eixos x
e y
são
positivos para baixo. Portanto, o valor MaxChartValue
sempre será menor que o
MinChartValue
. Portanto, a política de combinação é min
para o valor de referência máximo
dos dados do gráfico e max
para o valor de referência mínimo dos dados do gráfico.
Ao criar um Layout
ou LayoutModifier
personalizado, especifique linhas de alinhamento
personalizadas no método
MeasureScope.layout
, que usa um parâmetro
alignmentLines: Map<AlignmentLine, Int>
.
@Composable private fun BarChart( dataPoints: List<Int>, modifier: Modifier = Modifier, ) { val maxValue: Float = remember(dataPoints) { dataPoints.maxOrNull()!! * 1.2f } BoxWithConstraints(modifier = modifier) { val density = LocalDensity.current with(density) { // ... // Calculate baselines val maxYBaseline = // ... val minYBaseline = // ... Layout( content = {}, modifier = Modifier.drawBehind { // ... } ) { _, constraints -> with(constraints) { layout( width = if (hasBoundedWidth) maxWidth else minWidth, height = if (hasBoundedHeight) maxHeight else minHeight, // Custom AlignmentLines are set here. These are propagated // to direct and indirect parent composables. alignmentLines = mapOf( MinChartValue to minYBaseline.roundToInt(), MaxChartValue to maxYBaseline.roundToInt() ) ) {} } } } } }
Os pais diretos e indiretos desse elemento combinável podem consumir as linhas de
alinhamento. O seguinte elemento combinável cria um layout personalizado que usa como
parâmetro dois slots Text
e pontos de dados, e alinha os dois textos com os
valores máximos e mínimos do gráfico. A visualização desse elemento é
mostrada na Figura 2.
@Composable private fun BarChartMinMax( dataPoints: List<Int>, maxText: @Composable () -> Unit, minText: @Composable () -> Unit, modifier: Modifier = Modifier, ) { Layout( content = { maxText() minText() // Set a fixed size to make the example easier to follow BarChart(dataPoints, Modifier.size(200.dp)) }, modifier = modifier ) { measurables, constraints -> check(measurables.size == 3) val placeables = measurables.map { it.measure(constraints.copy(minWidth = 0, minHeight = 0)) } val maxTextPlaceable = placeables[0] val minTextPlaceable = placeables[1] val barChartPlaceable = placeables[2] // Obtain the alignment lines from BarChart to position the Text val minValueBaseline = barChartPlaceable[MinChartValue] val maxValueBaseline = barChartPlaceable[MaxChartValue] layout(constraints.maxWidth, constraints.maxHeight) { maxTextPlaceable.placeRelative( x = 0, y = maxValueBaseline - (maxTextPlaceable.height / 2) ) minTextPlaceable.placeRelative( x = 0, y = minValueBaseline - (minTextPlaceable.height / 2) ) barChartPlaceable.placeRelative( x = max(maxTextPlaceable.width, minTextPlaceable.width) + 20, y = 0 ) } } } @Preview @Composable private fun ChartDataPreview() { MaterialTheme { BarChartMinMax( dataPoints = listOf(4, 24, 15), maxText = { Text("Max") }, minText = { Text("Min") }, modifier = Modifier.padding(24.dp) ) } }
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Gráficos no Compose
- Layouts personalizados {:#custom-layouts }
- Medidas intrínsecas em layouts do Compose