Compose 版面配置模型可讓您使用 AlignmentLine
建立自訂的對齊線,上層布局可使用此線對齊和定位其子項。舉例來說,
Row
可以使用其子項的自訂對齊線來對齊。
如果版面配置提供特定 AlignmentLine
的值,版面配置的父項可以使用對應 Placeable
執行個體的 Placeable.get
運算子,在測量後讀取此值。根據 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 fun TextWithPaddingToBaselinePreview() { MaterialTheme { Text("Hi there!", Modifier.firstBaselineToTop(32.dp)) } }
為讀取範例中的 FirstBaseline
,測量階段會使用 placeable [FirstBaseline]
。
建立自訂對齊線
建立自訂 Layout
可組合項或自訂 LayoutModifier
時,您可以提供自訂對齊線,讓其他父項可組合元件可以使用該線,並且據此決定子項的位置。
以下範例顯示自訂 BarChart
可組合項,其中顯示 MaxChartValue
和 MinChartValue
兩個對齊線,因此其他可組合元素能符合圖表的最大和最小資料值。兩個文字元素 (Max 和 Min) 已經在自訂對齊線的中心對齊。
圖 2. BarChart
可組合項的文字符合資料的最大值和最小值。
自訂對齊線行在專案中定義為頂層變數。
import kotlin.math.max
import kotlin.math.min
import androidx.compose.ui.layout.HorizontalAlignmentLine
/**
* AlignmentLine defined by the maximum data value in a [BarChart]
*/
val MaxChartValue = HorizontalAlignmentLine(merger = { old, new -> min(old, new) })
/**
* AlignmentLine defined by the minimum data value in a [BarChart]
*/
val MinChartValue = HorizontalAlignmentLine(merger = { old, new -> max(old, new) })
用來建立範例的自訂對齊線是 HorizontalAlignmentLine
類型,因為它們是用於垂直對齊子項。如果有多個版面配置為這些對齊線提供值,系統會傳遞合併政策作為參數。當
Compose 版面配置系統座標和 Canvas
座標代表 [0, 0]
時,左上角以及 x
和 y
軸會是
正向朝下,因此 MaxChartValue
值將始終小於
MinChartValue
。因此,最大圖表資料值基準的合併政策為 min
,最小圖表資料值基準的合併政策為 max
。
建立自訂 Layout
或 LayoutModifier
時,請在使用 alignmentLines: Map<AlignmentLine, Int>
參數的 MeasureScope.layout
方法中指定自訂對齊線。
@Composable
fun BarChart(
dataPoints: List<Int>,
modifier: Modifier = Modifier
) {
/* ... */
BoxWithConstraints(modifier = modifier) {
// Calculate custom AlignmentLines: minYBaseline and maxYBaseline
val maxYBaseline = /* ... */
val minYBaseline = /* ... */
Layout(
content = {},
modifier = Modifier.drawBehind {
// Logic to draw the Chart
}
) { _, 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
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
fun ChartDataPreview() {
MaterialTheme {
BarChartMinMax(
dataPoints = listOf(4, 24, 15),
maxText = { Text("Max") },
minText = { Text("Min") },
modifier = Modifier.padding(24.dp)
)
}
}