Compose 的其中一項規則是只能測量子項一次;如果測量子項兩次,系統將擲回執行階段例外狀況。不過有時候,您必須先掌握子項的某些相關資訊,才能進行測量。
內建函式可讓您在實際測量前查詢子項相關資訊。
如果是可組合項,您可以查詢其 intrinsicWidth
或 intrinsicHeight
:
(min|max)IntrinsicWidth
:依據這個寬度,您可以正確繪製內容的最小/最大寬度為何?(min|max)IntrinsicHeight
:依據這個高度,您可以正確繪製內容的最小/最大高度為何?
舉例來說,如果在 height
設為無限的情況下查詢 Text
的 minIntrinsicHeight
,系統會將文字視為繪製在單一直線上並傳回 Text
的 height
。
內建函式實際使用狀況
假設我們要建立一個可組合項,在畫面上顯示兩個文字元素並以分隔線隔開,如下所示:
我們該怎麼做?我們可以設定一個 Row
,在當中加入兩個 Text
並盡可能擴大兩者之間的距離,然後在中間加入一個 Divider
。我們將 Divider
的高度設為 Text
的最大高度,寬度則為細 (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 ) HorizontalDivider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } }
在預覽畫面中,我們發現 Divider
會擴展至整個畫面,這並非我們想要的結果:
之所以會發生這種情況,原因是 Row
會個別測量每個子項,而 Text
的高度無法用於限制 Divider
。我們想讓 Divider
填滿指定高度的可用空間。想達到這個目的,我們可以使用 height(IntrinsicSize.Min)
修飾符。
height(IntrinsicSize.Min)
會將子項的高度強制調整為內建函式的最低高度。由於該修飾符有遞迴性,因此會查詢 Row
和其子項的 minIntrinsicHeight
。
套用到我們的程式碼後,就能產生我們預期的結果:
@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 ) HorizontalDivider( 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") } } }
預覽如下:
Row
可組合項的 minIntrinsicHeight
將是其子項的 minIntrinsicHeight
上限。由於 Divider
元素在沒有限制條件的情況下不會占用空間,因此其 minIntrinsicHeight
為 0,而在指定特定 width
的情況下,Text
minIntrinsicHeight
將為文字的高度。因此,Row
元素的 height
限制將是 Text
的 minIntrinsicHeight
上限。Divider
隨即會將其 height
擴展至 Row
指定的 height
限制。
自訂版面配置中的內建函式
建立自訂 Layout
或 layout
修飾符時,系統會根據估計值自動計算內建函式測量結果。因此,這些計算結果的正確性會依版面配置而異。這些 API 會提供覆寫這些預設值的選項。
如要指定自訂 Layout
的內建函式測量資料,請在建立 MeasurePolicy
介面時覆寫 minIntrinsicWidth
、minIntrinsicHeight
、maxIntrinsicWidth
和 maxIntrinsicHeight
。
@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. } ) }
建立自訂 layout
修飾符時,請在 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. }
為您推薦
- 注意:系統會在 JavaScript 關閉時顯示連結文字
- 自訂版面配置 {:#custom-layouts }
- Jetpack Compose 中的對齊線
- Jetpack Compose 階段