Im Layoutmodell „Compose“ können Sie mit AlignmentLine
benutzerdefinierte Ausrichtungslinien erstellen, die von übergeordneten Layouts zum Ausrichten und Positionieren der untergeordneten Elemente verwendet werden können. Row
kann beispielsweise die benutzerdefinierten Ausrichtungslinien der untergeordneten Elemente verwenden, um sie auszurichten.
Wenn ein Layout einen Wert für eine bestimmte AlignmentLine
bereitstellt, können die übergeordneten Elemente des Layouts diesen Wert nach dem Messen lesen, indem sie den Operator Placeable.get
auf der entsprechenden Instanz Placeable
verwenden.
Anhand der Position von AlignmentLine
können die übergeordneten Elemente dann die Positionierung der untergeordneten Elemente festlegen.
Einige zusammensetzbare Funktionen in „Schreiben“ sind bereits mit Ausrichtungslinien ausgestattet. Beispielsweise werden in der zusammensetzbaren Funktion BasicText
die Ausrichtungslinien FirstBaseline
und LastBaseline
angezeigt.
Im folgenden Beispiel liest ein benutzerdefiniertes LayoutModifier
namens firstBaselineToTop
den FirstBaseline
, um dem Text
beginnend mit der ersten Referenz einen Innenrand hinzuzufügen.
Abbildung 1: Zeigt den Unterschied zwischen dem Hinzufügen eines normalen Innenrands für ein Element und dem Anwenden eines Innenrands auf die Referenz eines Textelements.
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)) } }
Zum Lesen der FirstBaseline
im Beispiel wird placeable [FirstBaseline]
in der Messphase verwendet.
Benutzerdefinierte Ausrichtungslinien erstellen
Wenn Sie eine benutzerdefinierte Layout
- oder eine benutzerdefinierte LayoutModifier
erstellen, können Sie benutzerdefinierte Ausrichtungslinien angeben, damit andere übergeordnete zusammensetzbare Funktionen sie verwenden können, um ihre untergeordneten Elemente entsprechend auszurichten und zu positionieren.
Das folgende Beispiel zeigt eine benutzerdefinierte zusammensetzbare Funktion BarChart
, die zwei Ausrichtungslinien, MaxChartValue
und MinChartValue
, enthält, damit andere zusammensetzbare Funktionen am maximalen und minimalen Datenwert des Diagramms ausgerichtet werden können. Die beiden Textelemente Max und Min wurden an der Mitte der benutzerdefinierten Ausrichtungslinien ausgerichtet.
Abbildung 2: BarChart
kann mit Text zusammensetzbar sein, der auf den Höchst- und Mindestwert ausgerichtet ist.
Benutzerdefinierte Ausrichtungslinien werden als Variablen der obersten Ebene in Ihrem Projekt definiert.
/** * 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) })
Die benutzerdefinierten Ausrichtungslinien, mit denen wir unser Beispiel erstellen, sind vom Typ HorizontalAlignmentLine
, da sie verwendet werden, um untergeordnete Elemente vertikal auszurichten. Für den Fall, dass mehrere Layouts einen Wert für diese Ausrichtungslinien bereitstellen, wird eine Zusammenführungsrichtlinie als Parameter übergeben. Da die Koordinaten des Layoutsystems und die Canvas
-Koordinaten [0, 0]
darstellen, sind die obere linke Ecke sowie die Achse x
und y
nach unten positiv, sodass der Wert MaxChartValue
immer kleiner als MinChartValue
ist. Daher lautet die Fusionsrichtlinie min
für die maximale Referenz des Diagrammdatenwerts und max
für die minimale Referenzwert der Diagrammdaten.
Geben Sie beim Erstellen eines benutzerdefinierten Layout
- oder LayoutModifier
-Elements in der Methode MeasureScope.layout
benutzerdefinierte Ausrichtungslinien an, für die ein alignmentLines: Map<AlignmentLine, Int>
-Parameter verwendet wird.
@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() ) ) {} } } } } }
Direkte und indirekte übergeordnete und indirekte übergeordnete dieser zusammensetzbaren Funktion können die Ausrichtungslinien nutzen. Die folgende zusammensetzbare Funktion erstellt ein benutzerdefiniertes Layout, das zwei Text
-Slots und Datenpunkte als Parameter verwendet und die beiden Texte an den maximalen und minimalen Diagrammdatenwerten ausrichtet. Eine Vorschau dieser zusammensetzbaren Funktion
ist in Abbildung 2 zu sehen.
@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) ) } }
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Grafiken in „Compose“
- Benutzerdefinierte Layouts {:#custom-layouts }
- Intrinsische Messungen in „Layouts erstellen“