Mit dem Compose-Layoutmodell können Sie mit AlignmentLine benutzerdefinierte Ausrichtungslinien erstellen, die von übergeordneten Layouts zum Ausrichten und Positionieren ihrer untergeordneten Elemente verwendet werden können. 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 Kinder festlegen.
Einige Composables in Compose haben bereits Ausrichtungslinien. Die zusammensetzbare Funktion BasicText macht beispielsweise die Ausrichtungslinien FirstBaseline und LastBaseline verfügbar.
Im folgenden Beispiel wird ein benutzerdefiniertes LayoutModifier namens firstBaselineToTop verwendet, um die FirstBaseline zu lesen und der Text ab der ersten Baseline einen Innenabstand hinzuzufügen.
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.
BarChart, die mit Text ausgerichtet auf den maximalen und minimalen Datenwert zusammengesetzt werden kann.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, wenn 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