Model układu w Compose umożliwia użycie AlignmentLine
do tworzenia niestandardowych linii wyrównania, których układy nadrzędne mogą używać do wyrównywania i pozycjonowania elementów podrzędnych. Na przykład element Row
może używać niestandardowych linii wyrównania swoich podrzędnych elementów, aby je wyrównać.
Gdy układ podaje wartość dla określonego parametru AlignmentLine
, jego rodzice mogą odczytać tę wartość po zmierzeniu, używając operatora Placeable.get
w odpowiednim wystąpieniu Placeable
.
Na podstawie pozycji AlignmentLine
rodzice mogą zdecydować o pozycji dzieci.
Niektóre komponenty w Compose mają już linie wyrównania. Na przykład komponent BasicText
udostępnia linie wyrównania FirstBaseline
i LastBaseline
.
W przykładzie poniżej niestandardowa funkcja LayoutModifier
o nazwie firstBaselineToTop
odczytuje dane z elementu FirstBaseline
, aby dodać wypełnienie do elementu Text
, zaczynając od jego pierwszej wartości odniesienia.
Rysunek 1. Pokazuje różnicę między dodaniem normalnego wypełnienia do elementu a zastosowaniem wypełnienia do linii bazowej elementu tekstowego.
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)) } }
Aby odczytać wartość FirstBaseline
w tym przykładzie, w fazie pomiaru używana jest wartość placeable [FirstBaseline]
.
Tworzenie niestandardowych linii wyrównania
Podczas tworzenia niestandardowego komponentu Layout
lub niestandardowego komponentu LayoutModifier
możesz dodać niestandardowe linie wyrównania, aby inne komponenty nadrzędne mogły ich używać do wyrównywania i odpowiedniego pozycjonowania komponentów podrzędnych.
W tym przykładzie pokazano komponent własny BarChart
, który udostępnia 2 linie wyrównania, MaxChartValue
i MinChartValue
, aby inne komponenty mogły się dopasować do maksymalnej i minimalnej wartości danych na wykresie. 2 elementy tekstowe, Max i Min, zostały wyrównane do środka niestandardowych linii wyrównania.
Rysunek 2. Funkcja BarChart
kompozycyjna z tekstem wyrównanym do maksymalnej i minimalnej wartości danych.
Niestandardowe linie wyrównania są definiowane jako zmienne najwyższego poziomu w projekcie.
/** * 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) })
Niestandardowe linie wyrównania do utworzenia naszego przykładu są typu HorizontalAlignmentLine
, ponieważ służą do wyrównywania elementów podrzędnych w pionie. Jeśli wiele układów zawiera wartość dla tych linii wyrównania, jako parametr przekazywana jest zasada łączenia. Współrzędne systemu układu w Compose i współrzędne Canvas
odpowiadają [0, 0]
, a lewy górny róg oraz osie x
i y
są dodatnie skierowane w dół, więc wartość MaxChartValue
będzie zawsze mniejsza od wartości MinChartValue
. Dlatego polityka łączenia to min
dla maksymalnego punktu odniesienia wartości danych na wykresie oraz max
dla minimalnego punktu odniesienia wartości danych na wykresie.
Podczas tworzenia niestandardowego obiektu Layout
lub LayoutModifier
określ niestandardowe wiersze w metodzie MeasureScope.layout
, która przyjmuje parametr 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() ) ) {} } } } } }
Bezpośredni i pośredni rodzic tego komponentu może używać linii wyrównania. Poniższa kompozycja tworzy układ niestandardowy, który przyjmuje jako parametry 2 boksy Text
i punkty danych, a następnie wyrównuje 2 teksty do wartości maksymalnych i minimalnych danych wykresu. Podgląd tego elementu kompozycyjnego
pokazuje się na ilustracji 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) ) } }
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy obsługa JavaScript jest wyłączona
- Grafika w Compose
- Układy niestandardowe {:#custom-layouts }
- Własne pomiary w układach tworzenia wiadomości