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)
– Bạn cần chiều rộng tối thiểu bao nhiêu để hiển thị nội dung một cách phù hợp?Modifier.width(IntrinsicSize.Max)
– Bạn cần chiều rộng tối đa bao nhiêu để hiển thị nội dung một cách phù hợp?Modifier.height(IntrinsicSize.Min)
– Bạn cần chiều cao tối thiểu bao nhiêu để hiển thị nội dung một cách phù hợp?Modifier.height(IntrinsicSize.Max)
– Bạn cần chiều cao tối đa bao nhiêu để hiển thị nội dung một cách phù hợp?
Ví dụ: nếu bạn yêu cầu minIntrinsicHeight
của một Text
có các quy tắ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ế
Hãy tưởng tượng chúng ta muốn tạo một thành phần kết hợp có thể 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 như sau:
Chúng ta có thể làm việc này bằng cách nào? Chúng ta có thể có một Row
với hai Text
bên trong mở rộng nhiều nhất có thể và một Divider
ở giữa. Chúng ta muốn Divider
cao bằng Text
cao nhất và 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 ) } }
Nếu xem trước, chúng ta sẽ thấy Divider
mở rộng ra toàn màn hình và đó không phải là điều chúng ta 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
. Chúng ta muốn Divider
lấp đầy không gian hiện có với một chiều cao nhất định. Do đó, chúng ta có thể sử dụng phương thức 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ì có tính đệ quy, lượt truy vấn này sẽ truy vấn Row
và cũng như minIntrinsicHeight
của thành phần con.
Khi áp dụng mã đó, mã sẽ hoạt động như mong đợi:
@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:
minIntrinsicHeight
của thành phần kết hợp Row
sẽ 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
sẽ bằng của văn bản đã cung cấp một width
cụ thể. Do đó, điều kiện ràng buộc height
của phần tử Row
sẽ là minIntrinsicHeight
tối đa của Text
. Sau đó, Divider
sẽ mở rộng height
tới giới hạn height
do Row
đư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. }
Hiện không có đề xuất nào.
Hãy thử đăng nhập vào Tài khoản Google của bạn.