Модель макета Compose позволяет использовать AlignmentLine
для создания настраиваемых линий выравнивания, которые родительские макеты могут использовать для выравнивания и позиционирования дочерних элементов. Например, Row
может использовать настраиваемые линии выравнивания дочерних элементов для их выравнивания.
Когда макет предоставляет значение для конкретного AlignmentLine
, родительские элементы макета могут прочитать это значение после измерения, используя оператор Placeable.get
для соответствующего экземпляра Placeable
. Исходя из положения AlignmentLine
, родительские элементы могут затем определить положение дочерних элементов.
Некоторые компонуемые элементы в Compose уже имеют линии выравнивания. Например, компонуемый элемент BasicText
отображает линии выравнивания FirstBaseline
и LastBaseline
.
В примере ниже пользовательский LayoutModifier
с именем firstBaselineToTop
считывает FirstBaseline
, чтобы добавить отступ к Text
, начиная с его первой базовой линии.
Рисунок 1. Демонстрирует разницу между добавлением обычного отступа к элементу и применением отступа к базовой линии текстового элемента.
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)) } }
Для считывания FirstBaseline
в примере на этапе измерения используется placeable [FirstBaseline]
.
Создавайте пользовательские линии выравнивания
При создании пользовательского компонуемого Layout
или пользовательского LayoutModifier
можно указать пользовательские линии выравнивания, чтобы другие родительские компонуемые элементы могли использовать их для выравнивания и соответствующего позиционирования своих дочерних элементов.
В следующем примере показана пользовательская компонуемая диаграмма BarChart
, которая отображает две линии выравнивания, MaxChartValue
и MinChartValue
, чтобы другие компонуемые элементы могли выравниваться по максимальному и минимальному значению данных диаграммы. Два текстовых элемента, Max и Min , выровнены по центру пользовательских линий выравнивания.
Рисунок 2. BarChart
, компонуемая с текстом, выровненным по максимальному и минимальному значению данных.
Пользовательские линии выравнивания определяются как переменные верхнего уровня в вашем проекте.
/** * 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) })
Пользовательские линии выравнивания для создания нашего примера имеют тип HorizontalAlignmentLine
, поскольку они используются для вертикального выравнивания дочерних элементов. Политика слияния передаётся в качестве параметра, если несколько макетов предоставляют значение для этих линий выравнивания. Поскольку системные координаты макета Compose и координаты Canvas
представляют собой [0, 0]
, верхний левый угол и оси x
и y
имеют положительное направление вниз, поэтому значение MaxChartValue
всегда будет меньше MinChartValue
. Следовательно, политика слияния — min
для максимального базового значения данных диаграммы и max
для минимального базового значения данных диаграммы.
При создании пользовательского Layout
или LayoutModifier
укажите пользовательские линии выравнивания в методе MeasureScope.layout
, который принимает параметр 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() ) ) {} } } } } }
Прямые и косвенные родительские элементы этого компонуемого объекта могут использовать линии выравнивания . Следующий компонуемый объект создаёт пользовательский макет, который принимает в качестве параметров два Text
слота и точки данных и выравнивает два текста по максимальному и минимальному значениям данных диаграммы. Предварительный просмотр этого компонуемого объекта показан на рисунке 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) ) } }
Рекомендовано для вас
- Примечание: текст ссылки отображается, когда JavaScript отключен.
- Графика в Compose
- Пользовательские макеты {:#custom-layouts }
- Внутренние измерения в макетах Compose