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:
minIntrinsicHeightcủa thành phần kết hợpRowlàminIntrinsicHeighttối đa của thành phần con.minIntrinsicHeightcủa phần tửDividerlà 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.TextminIntrinsicHeightlà của văn bản cho mộtwidthcụ thể.- Do đó, điều kiện ràng buộc
heightcủa phần tửRowsẽ trở thànhminIntrinsicHeighttối đa củaText. - Sau đó,
Dividersẽ mở rộngheightđến giới hạnheightdoRowđư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