Il modello di layout di composizione ti consente di utilizzare AlignmentLine
per creare linee di allineamento personalizzate che possono essere utilizzate dai layout principali per allineare e posizionare i layout 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
, gli elementi di primo livello 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 poi decidere il posizionamento dei bambini.
Alcuni composabili in Compose sono già dotati di linee di allineamento. Ad esempio, il composable
BasicText
mostra le linee di allineamento FirstBaseline
e LastBaseline
.
Nell'esempio seguente, un LayoutModifier
personalizzato chiamato
firstBaselineToTop
legge il FirstBaseline
per aggiungere spaziatura al Text
a partire dalla prima linea di base.
Figura 1. Mostra la differenza tra l'aggiunta di un normale spaziatura interna a un elemento e l'applicazione di spaziatura interna alla linea di base di un elemento di testo.
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 FirstBaseline
nell'esempio,
placeable [FirstBaseline]
viene utilizzato nella fase di misurazione.
Creare linee di allineamento personalizzate
Quando crei un composable Layout
personalizzato o un LayoutModifier
personalizzato, puoi fornire linee di allineamento personalizzate in modo che altri composabili principali possano utilizzarle per allineare e posizionare di conseguenza i propri elementi secondari.
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.
Figura 2. BarChart
componibile con il 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
, poiché
vengono utilizzate per allineare gli elementi secondari verticalmente. Un criterio di unione viene passato 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
represent[0, 0]
, l'angolo in alto a sinistra e gli assi x
e y
sono positivi verso il basso, quindi il valore MaxChartValue
sarà sempre inferiore aMinChartValue
. Pertanto, il criterio di unione è min
per la base di riferimento del valore dei dati del grafico massimo e max
per la base di riferimento del valore dei dati del grafico minimo.
Quando crei un Layout
o un LayoutModifier
personalizzato, specifica 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() ) ) {} } } } } }
I componenti diretti e indiretti di questo composable possono utilizzare le linee di allineamento. Il seguente composable crea un layout personalizzato che prende come parametro due slot Text
e punti dati e allinea i due testi ai valori massimi e minimi dei dati del grafico. L'anteprima di questo composable è rappresentata 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