Mô hình bố cục trong Compose cho phép bạn sử dụng AlignmentLine
để tạo
các dòng căn chỉnh tuỳ chỉnh có thể được bố cục mẹ sử dụng để căn chỉnh và đặt vị trí
thành phần con cháu. Ví dụ:
Row
có thể dùng các dòng căn chỉnh tuỳ chỉnh của thành phần con cháu để căn chỉnh.
Khi bố cục cung cấp một giá trị cho một AlignmentLine
cụ thể, thành phần mẹ của bố cục có thể đọc giá trị này sau khi đo lường, sử dụng toán tử Placeable.get
trên thực thể Placeable
tương ứng.
Sau đó, dựa vào vị trí của AlignmentLine
, thành phần mẹ có thể
quyết định vị trí của thành phần con cháu.
Một số thành phần kết hợp trong Compose đã có dòng căn chỉnh. Ví dụ: thành phần kết hợp
BasicText
hiển thị dòng căn chỉnh FirstBaseline
và LastBaseline
.
Trong ví dụ bên dưới, LayoutModifier
tuỳ chỉnh có tên
firstBaselineToTop
đọc FirstBaseline
để thêm khoảng đệm vào Text
bắt đầu từ đường cơ sở đầu tiên.
Hình 1. Thể hiện sự khác biệt giữa việc thêm khoảng đệm thông thường vào một thành phần và áp dụng khoảng đệm vào đường cơ sở của thành phần văn bản.
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)) } }
Để đọc FirstBaseline
trong ví dụ,
placeable [FirstBaseline]
được sử dụng trong giai đoạn đo lường.
Tạo đường căn chỉnh tuỳ chỉnh
Khi tạo một thành phần kết hợp Layout
tuỳ chỉnh hoặc một LayoutModifier
tuỳ chỉnh, bạn có thể cung cấp dòng căn chỉnh tuỳ chỉnh để các thành phần kết hợp mẹ khác có thể sử dụng để căn chỉnh và định vị thành phần con cháu phù hợp.
Ví dụ sau đây thể hiện một thành phần kết hợp BarChart
tuỳ chỉnh hiển thị 2 dòng căn chỉnh, MaxChartValue
và MinChartValue
, để các thành phần kết hợp khác có thể căn chỉnh theo giá trị dữ liệu tối đa và tối thiểu của biểu đồ. Hai thành phần
văn bản, Tối đa và Tối thiểu, đã được căn chỉnh ở chính giữa
các dòng căn chỉnh tuỳ chỉnh.
Hình 2. BarChart
có thể kết hợp với Văn bản được căn chỉnh theo giá trị dữ liệu tối đa và
tối thiểu.
Các dòng căn chỉnh tuỳ chỉnh được xác định là các biến cấp cao nhất trong dự án của bạn.
/** * 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) })
Các dòng căn chỉnh tuỳ chỉnh để làm ví dụ thuộc loại
HorizontalAlignmentLine
, được dùng để
căn chỉnh thành phần con cháu theo chiều dọc. Chính sách hợp nhất được truyền khi
một thông số trong trường hợp nhiều bố cục cung cấp một giá trị cho các dòng căn chỉnh này. Khi
toạ độ hệ thống bố cục của Compose và tọa độ Canvas
đại diện cho [0, 0]
, thì góc trên cùng bên trái cùng trục x
và y
là chiều dương hướng xuống dưới, vì vậy, giá trị MaxChartValue
sẽ luôn nhỏ hơn
MinChartValue
. Do đó, chính sách hợp nhất là min
đối với đường cơ sở giá trị dữ liệu biểu đồ tối đa
và max
đối với đường cơ sở giá trị dữ liệu biểu đồ tối thiểu.
Khi tạo Layout
hoặc LayoutModifier
tuỳ chỉnh, hãy chỉ định các dòng căn chỉnh
tuỳ chỉnh trong phương thức MeasureScope.layout
Phương thức này sẽ có một thông số
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() ) ) {} } } } } }
Thành phần mẹ trực tiếp và gián tiếp của thành phần kết hợp này có thể sử dụng
dòng căn chỉnh. Thành phần kết hợp sau đây tạo ra một bố cục tuỳ chỉnh có
thông số hai khe Text
và các điểm dữ liệu, đồng thời sắp xếp hai văn bản này
theo giá trị dữ liệu biểu đồ tối đa và tối thiểu. Bản xem trước của thành phần kết hợp này
là nội dung biểu thị trong Hình 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) ) } }
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Đồ hoạ trong Compose
- Bố cục tuỳ chỉnh {:#custom-layouts }
- Phép đo nội tại trong bố cục Compose