Compose 레이아웃 모델을 사용하면 AlignmentLine
을 사용하여 맞춤 정렬 선을 만들 수 있습니다. 이 맞춤 정렬 선은 하위 요소를 정렬하고 위치를 지정할 때 상위 요소 레이아웃에 사용할 수 있습니다. 예를 들어 Row
는 하위 요소의 맞춤 정렬 선을 사용하여 하위 요소를 정렬할 수 있습니다.
레이아웃에서 특정 AlignmentLine
값을 제공하는 경우 레이아웃의 상위 요소는 대응하는 Placeable
인스턴스에 Placeable.get
연산자를 사용하여 이 값을 측정 후 읽어올 수 있습니다.
그러면 AlignmentLine
의 위치에 따라 상위 요소는 하위 요소의 위치 지정을 결정할 수 있습니다.
Compose의 일부 컴포저블에는 이미 정렬 선이 함께 제공됩니다. 예를 들어 BasicText
컴포저블은 FirstBaseline
및 LastBaseline
정렬 선을 노출합니다.
아래 예에서 firstBaselineToTop
이라는 맞춤 LayoutModifier
는 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
를 만들 때 맞춤 정렬 선을 제공할 수 있습니다. 그러면 다른 상위 컴포저블이 그 정렬 선을 사용하여 그에 따라 하위 요소를 정렬하고 위치를 지정할 수 있습니다.
다음 예에서는 다른 컴포저블을 차트의 최대 및 최소 데이터 값에 정렬할 수 있도록 두 개의 정렬 선 MaxChartValue
와 MinChartValue
를 노출하는 맞춤 BarChart
컴포저블을 보여줍니다. 두 개의 텍스트 요소 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)
)
}
}