Compose có một quy tắc là bạn chỉ nên đo lường thành phần con một lần; việc đo lường thành phần con hai lần sẽ cho ra một ngoại lệ trong thời gian chạy. Tuy nhiên, có một số trường hợp bạn cần thêm thông tin về thành phần con trước khi đo lường.
Hàm nội tại (intrinsics) cho phép bạn truy vấn thành phần con trước khi thực sự đo lường.
Đối với thành phần kết hợp, bạn có thể yêu cầu IntrinsicSize.Min
hoặc IntrinsicSize.Max
:
Modifier.width(IntrinsicSize.Min)
– Chiều rộng tối thiểu cần thiết để hiển thị nội dung của bạn một cách phù hợp là bao nhiêu?Modifier.width(IntrinsicSize.Max)
– Bạn cần chiều rộng tối đa là bao nhiêu để hiển thị nội dung một cách phù hợp?Modifier.height(IntrinsicSize.Min)
– Chiều cao tối thiểu cần thiết để hiển thị nội dung một cách phù hợp là bao nhiêu?Modifier.height(IntrinsicSize.Max)
– Chiều cao tối đa bạn cần để hiển thị nội dung một cách phù hợp là bao nhiêu?
Ví dụ: nếu bạn yêu cầu minIntrinsicHeight
của một Text
có các ràng buộc width
vô hạn trong một bố cục tuỳ chỉnh, thì thao tác này sẽ trả về height
của Text
với văn bản được vẽ trong một dòng duy nhất.
Hàm nội tại trong thực tế
Bạn có thể tạo một thành phần kết hợp hiển thị hai đoạn văn bản trên màn hình được phân tách bằng một đường phân cách:
Để làm việc này, hãy dùng một Row
có 2 thành phần kết hợp Text
lấp đầy không gian có sẵn và một Divider
ở giữa. Divider
phải cao bằng Text
cao nhất và phải hẹp (width = 1.dp
).
@Composable fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) { Row(modifier = modifier) { Text( modifier = Modifier .weight(1f) .padding(start = 4.dp) .wrapContentWidth(Alignment.Start), text = text1 ) VerticalDivider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } }
Divider
mở rộng ra toàn màn hình, đây không phải là hành vi mong muốn:
Điều này xảy ra vì Row
đo lường từng thành phần con riêng lẻ và không thể sử dụng chiều cao của Text
để ràng buộc Divider
.
Để Divider
lấp đầy không gian hiện có với một chiều cao nhất định, hãy sử dụng đối tượng sửa đổi height(IntrinsicSize.Min)
.
height(IntrinsicSize.Min)
cho phép thành phần con cao hơn chiều cao nội tại tối thiểu. Vì đối tượng sửa đổi này có tính đệ quy, nên nó sẽ truy vấn minIntrinsicHeight
của Row
và các thành phần con của thành phần này.
Khi áp dụng đối tượng sửa đổi này vào mã, mã sẽ hoạt động như dự kiến:
@Composable fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) { Row(modifier = modifier.height(IntrinsicSize.Min)) { Text( modifier = Modifier .weight(1f) .padding(start = 4.dp) .wrapContentWidth(Alignment.Start), text = text1 ) VerticalDivider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } } // @Preview @Composable fun TwoTextsPreview() { MaterialTheme { Surface { TwoTexts(text1 = "Hi", text2 = "there") } } }
Bản xem trước:
Chiều cao của Row
được xác định như sau:
minIntrinsicHeight
của thành phần kết hợpRow
làminIntrinsicHeight
tối đa của thành phần con.minIntrinsicHeight
của phần tửDivider
là 0 vì không chiếm dung lượng nếu không có điều kiện ràng buộc nào được đưa ra.Text
minIntrinsicHeight
là của văn bản cho mộtwidth
cụ thể.- Do đó, điều kiện ràng buộc
height
của phần tửRow
sẽ trở thànhminIntrinsicHeight
tối đa củaText
. - Sau đó,
Divider
sẽ mở rộngheight
đến giới hạnheight
doRow
đưa ra.
Hàm nội tại trong bố cục tuỳ chỉnh
Khi tạo một phương thức sửa đổi Layout
hoặc layout
tuỳ chỉnh, hàm đo lường nội tại sẽ được tự động tính toán dựa trên giá trị gần đúng. Do đó, cách tính có thể không chính xác cho tất cả bố cục. Các API này có các tuỳ chọn để ghi đè những giá trị mặc định như vậy.
Để chỉ định các phép đo hàm nội tại của Layout
tuỳ chỉnh, hãy ghi đè minIntrinsicWidth
, minIntrinsicHeight
, maxIntrinsicWidth
và maxIntrinsicHeight
của giao diện MeasurePolicy
khi tạo.
@Composable fun MyCustomComposable( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( content = content, modifier = modifier, measurePolicy = object : MeasurePolicy { override fun MeasureScope.measure( measurables: List<Measurable>, constraints: Constraints ): MeasureResult { // Measure and layout here // ... } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurables: List<IntrinsicMeasurable>, height: Int ): Int { // Logic here // ... } // Other intrinsics related methods have a default value, // you can override only the methods that you need. } ) }
Khi tạo phương thức sửa đổi layout
tuỳ chỉnh, hãy ghi đè các phương thức có liên quan trong giao diện LayoutModifier
.
fun Modifier.myCustomModifier(/* ... */) = this then object : LayoutModifier { override fun MeasureScope.measure( measurable: Measurable, constraints: Constraints ): MeasureResult { // Measure and layout here // ... } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurable: IntrinsicMeasurable, height: Int ): Int { // Logic here // ... } // Other intrinsics related methods have a default value, // you can override only the methods that you need. }
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Bố cục tuỳ chỉnh {:#custom-layouts}
- Đường căn chỉnh trong Jetpack Compose
- Các giai đoạn Jetpack Compose