Model układu w komponencie pozwala używać 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 konkretnego 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ą określić pozycję 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 wartość 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 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.
Ten przykład pokazuje 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. BarChart
z możliwością tworzenia z tekstem wyrównanym do wartości maksymalnej i minimalnej 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 użyte w naszym przykładzie są typu HorizontalAlignmentLine
, ponieważ służą do wyrównywania elementów pionowo. 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 Canvas
reprezentują [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 niż MinChartValue
. Dlatego polityka łączenia jest taka: min
dla maksymalnego punktu odniesienia wartości danych na wykresie oraz max
dla minimalnego punktu odniesienia wartości danych na wykresie.
Podczas tworzenia niestandardowego elementu Layout
lub LayoutModifier
określ niestandardowe wyrównanie linii 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. Podana niżej kompozycja tworzy układ niestandardowy, który przyjmuje jako parametry 2 boksy Text
i 2 punkty danych, a następnie wyrównuje oba teksty do wartości maksymalnych i minimalnych danych w wykresie. Podgląd tego komponentu jest widoczny na rysunku 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 sekcji Nowy post
- Układy niestandardowe {:#custom-layouts }
- Własne pomiary w układach tworzenia wiadomości