Il modello di layout di Scrivi consente di utilizzare AlignmentLine
per creare linee di allineamento personalizzate che possono essere utilizzate dai layout principali per allineare e posizionare i componenti figlio. Ad esempio,
Row
può utilizzare le linee di allineamento personalizzate degli elementi secondari per allinearle.
Quando un layout fornisce un valore per un determinato AlignmentLine
, i relativi valori principali possono leggere questo valore dopo la misurazione, utilizzando l'operatore Placeable.get
nell'istanza Placeable
corrispondente.
In base alla posizione del AlignmentLine
, i genitori possono
quindi decidere la posizione dei bambini.
Alcuni componibili in Compose hanno già linee di allineamento. Ad esempio, l'elemento componibile BasicText
espone le linee di allineamento FirstBaseline
e LastBaseline
.
Nell'esempio seguente, una LayoutModifier
personalizzata denominata
firstBaselineToTop
legge il FirstBaseline
per aggiungere spaziatura interna al Text
a partire dalla prima base di riferimento.
Figura 1. Mostra la differenza tra l'aggiunta di una normale spaziatura interna a un elemento e l'applicazione di una spaziatura interna alla base di riferimento 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.
Crea linee di allineamento personalizzate
Quando crei un elemento componibile Layout
personalizzato o una LayoutModifier
personalizzata, puoi fornire linee di allineamento personalizzate in modo che altri elementi componibili principali possano utilizzarle per allineare e posizionare i loro figli.
L'esempio seguente mostra un componibile BarChart
personalizzato che espone due righe di allineamento, MaxChartValue
e MinChartValue
, in modo che altri componibili possano essere allineati 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 personalizzato.
Figura 2. 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 tuo 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 trasmesso come parametro nel caso in cui più layout forniscano un valore per queste linee di allineamento. Poiché
le coordinate di 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, quindi il valore di MaxChartValue
sarà sempre inferiore a
MinChartValue
. Di conseguenza, il criterio di unione è min
per la base di riferimento massima del valore dei dati del grafico e max
per la base di riferimento del valore minimo dei dati del grafico.
Quando crei un elemento Layout
o LayoutModifier
personalizzato, specifica le righe di allineamento personalizzate nel metodo MeasureScope.layout
, che richiede 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 elementi principali diretti e indiretti di questo componibile possono consumare le righe di allineamento. Il seguente componibile crea un layout personalizzato che prende come parametro due slot Text
e punti dati e allinea i due testi ai valori massimo e minimo dei dati del grafico. L'anteprima di questo componibile è
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) ) } }
Consigliato per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Elementi grafici in Compose
- Layout personalizzati {:#custom-layouts }
- Misurazioni intrinseche nei layout di Compose