Il modello di layout di Compose ti consente di utilizzare AlignmentLine per creare linee di allineamento personalizzate che possono essere utilizzate dai layout principali per allineare e posizionare i relativi elementi secondari. Ad esempio, Row può utilizzare le linee di allineamento personalizzate dei suoi elementi secondari per allinearli.
Quando un layout fornisce un valore per un determinato AlignmentLine, i genitori del layout possono leggere questo valore dopo la misurazione, utilizzando l'operatore Placeable.get sull'istanza Placeable corrispondente. In base alla posizione del AlignmentLine, i genitori possono decidere la posizione dei figli.
Alcuni componibili in Compose sono già dotati di linee di allineamento. Ad esempio, il composable BasicText espone le linee di allineamento FirstBaseline e LastBaseline.
Nell'esempio seguente, un LayoutModifier personalizzato chiamato firstBaselineToTop legge FirstBaseline per aggiungere spaziatura interna a Text a partire dalla prima base di riferimento.
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)) } }
Per leggere il FirstBaseline nell'esempio, nella fase di misurazione viene utilizzato placeable [FirstBaseline].
Crea linee di allineamento personalizzate
Quando crei un Layout componibile personalizzato o un
LayoutModifier personalizzato, puoi fornire linee di allineamento personalizzate in modo che altri
componibili principali possano utilizzarle per allineare e posizionare i relativi elementi secondari
di conseguenza.
L'esempio seguente mostra un composable BarChart personalizzato che espone due
linee di allineamento, MaxChartValue e MinChartValue, in modo che altri composable
possano allinearsi al valore massimo e minimo dei dati del grafico. Due elementi di testo, Max e Min, sono stati allineati al centro delle linee di allineamento personalizzate.
BarChart componibile con testo allineato al valore massimo e minimo dei dati.Le linee di allineamento personalizzate sono definite come variabili di primo livello nel progetto.
/** * 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) })
Le linee di allineamento personalizzate per creare il nostro esempio sono di tipo HorizontalAlignmentLine, in quanto vengono utilizzate per allineare gli elementi secondari verticalmente. Una policy di unione viene passata come parametro nel caso in cui più layout forniscano un valore per queste linee di allineamento. Poiché le coordinate del sistema di layout di Compose e le coordinate Canvas rappresentano [0, 0], l'angolo in alto a sinistra e gli assi x e y sono positivi verso il basso, il valore MaxChartValue sarà sempre inferiore a MinChartValue. Pertanto, la policy di unione è min per la base di riferimento del valore massimo dei dati del grafico e max per la base di riferimento del valore minimo dei dati del grafico.
Quando crei un Layout o un LayoutModifier personalizzato, specifica le linee di allineamento personalizzate nel metodo MeasureScope.layout, che accetta un parametro 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() ) ) {} } } } } }
Gli elementi principali diretti e indiretti di questo componibile possono utilizzare le linee di allineamento. Il seguente componibile crea un layout personalizzato che accetta come parametro due slot Text e punti dati e allinea i due testi ai valori dei dati del grafico massimo e minimo. L'anteprima di questo composable è quella mostrata nella 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) ) } }
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Grafica in Compose
- Layout personalizzati {:#custom-layouts }
- Misurazioni intrinseche nei layout di Compose