O modelo de layout do Compose possibilita o uso de AlignmentLine para criar linhas de alinhamento personalizadas que podem ser usadas por layouts pais para alinhar e posicionar os
filhos. Por exemplo, Row pode usar as linhas de alinhamento personalizadas dos filhos
para alinhá-los.
Quando um layout fornece um valor para um determinado 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 FirstBaseline e LastBaseline
linhas de alinhamento.
No exemplo a seguir, um LayoutModifier chamado
firstBaselineToTop lê a FirstBaseline para adicionar padding ao Text
começando pela primeira linha de base.
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 o FirstBaseline no exemplo, placeable [FirstBaseline]
é usado na fase de medição.
Criar linhas de alinhamento personalizadas
Ao criar um combináveis Layout 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 combináveis BarChart 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.
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 Canvas
coordenadas 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
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.
- Elementos gráficos no Compose
- Layouts personalizados {:#custom-layouts }
- Medições intrínsecas em layouts do Compose