Mit dem Compose-Layoutmodell können Sie mit AlignmentLine
benutzerdefinierte Ausrichtungslinien erstellen, die von übergeordneten Layouts verwendet werden können, um ihre untergeordneten Elemente auszurichten und zu positionieren. Row
kann beispielsweise die benutzerdefinierten Ausrichtungslinien seiner untergeordneten Elemente verwenden, um sie auszurichten.
Wenn ein Layout einen Wert für ein bestimmtes AlignmentLine
bereitstellt, können die übergeordneten Elemente des Layouts diesen Wert nach der Messung mit dem Operator Placeable.get
für die entsprechende Placeable
-Instanz lesen.
Anhand der Position des AlignmentLine
können die Eltern dann die Positionierung der untergeordneten Elemente festlegen.
Einige Composables in Compose haben bereits Ausrichtungslinien. Die BasicText
-Composable-Funktion stellt beispielsweise die Ausrichtungslinien FirstBaseline
und LastBaseline
bereit.
Im Beispiel unten wird ein benutzerdefiniertes LayoutModifier
mit dem Namen firstBaselineToTop
verwendet, um die FirstBaseline
zu lesen und der Text
ab der ersten Baseline Padding hinzuzufügen.
Abbildung 1: Hier sehen Sie den Unterschied zwischen dem Hinzufügen von normalem Padding zu einem Element und dem Anwenden von Padding auf die Grundlinie 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)) } }
Um die FirstBaseline
im Beispiel zu lesen, wird placeable [FirstBaseline]
in der Messphase verwendet.
Benutzerdefinierte Ausrichtungslinien erstellen
Wenn Sie eine benutzerdefinierte Layout
-Composable oder eine benutzerdefinierte LayoutModifier
erstellen, können Sie benutzerdefinierte Ausrichtungslinien angeben, damit andere übergeordnete Composables sie verwenden können, um ihre untergeordneten Elemente entsprechend auszurichten und zu positionieren.
Im folgenden Beispiel wird ein benutzerdefiniertes BarChart
-Composable gezeigt, das zwei Ausrichtungslinien, MaxChartValue
und MinChartValue
, bereitstellt, damit andere Composables 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
, die mit Text ausgerichtet ist, der dem maximalen und minimalen Datenwert entspricht.
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 für unser Beispiel sind vom Typ HorizontalAlignmentLine
, da sie zum vertikalen Ausrichten von untergeordneten Elementen verwendet werden. Eine Zusammenführungsrichtlinie wird als Parameter übergeben, falls mehrere Layouts einen Wert für diese Ausrichtungslinien bereitstellen. Da die Koordinaten des Compose-Layoutsystems und die Canvas
-Koordinaten [0, 0]
darstellen, die obere linke Ecke und die x
- und y
-Achse positiv nach unten verlaufen, ist der MaxChartValue
-Wert immer kleiner als MinChartValue
. Daher ist die Zusammenführungsrichtlinie min
für die Baseline des maximalen Diagrammdatenwerts und max
für die Baseline des minimalen Diagrammdatenwerts.
Wenn Sie ein benutzerdefiniertes Layout
oder LayoutModifier
erstellen, geben Sie benutzerdefinierte Ausrichtungslinien in der Methode MeasureScope.layout
an, die einen alignmentLines: Map<AlignmentLine, Int>
-Parameter akzeptiert.
@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 Eltern dieses Composables können die Ausrichtungslinien verwenden. Mit dem folgenden Composable wird ein benutzerdefiniertes Layout erstellt, das zwei Text
-Slots und Datenpunkte als Parameter verwendet und die beiden Texte an den maximalen und minimalen Datenwerten des Diagramms ausrichtet. Die Vorschau dieser Komponente 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: Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Grafiken in Compose
- Benutzerdefinierte Layouts {:#custom-layouts }
- Integrierte Messungen in Compose-Layouts