Compose 的规则之一是,您只能测量子项一次;测量两次子项会抛出运行时异常。但是,有时您需要在测量子项之前获取有关它们的一些信息。
Intrinsics 允许您在子项实际测量之前查询它们。
对于可组合项,您可以请求其 IntrinsicSize.Min
或 IntrinsicSize.Max
。
Modifier.width(IntrinsicSize.Min)
- 显示内容所需的最小宽度是多少?Modifier.width(IntrinsicSize.Max)
- 显示内容所需的最大宽度是多少?Modifier.height(IntrinsicSize.Min)
- 显示内容所需的最小高度是多少?Modifier.height(IntrinsicSize.Max)
- 显示内容所需的最大高度是多少?
例如,如果您在自定义布局中请求具有无限 width
约束的 Text
的 minIntrinsicHeight
,它将返回文本绘制在单行中的 Text
的 height
。
Intrinsics 实战
想象一下,我们想创建一个可组合项,在屏幕上显示由分隔线分隔的两个文本,如下所示
我们如何做到这一点?我们可以有一个 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 ) 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
扩展到整个屏幕,而这并不是我们想要的。
发生这种情况是因为 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 ) 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") } } }
附带预览
Row
可组合项的 minIntrinsicHeight
将是其子项的最大 minIntrinsicHeight
。Divider
元素的 minIntrinsicHeight
为 0,因为它在未给定约束时不会占用空间;Text
的 minIntrinsicHeight
将是给定特定 width
的文本的高度。因此,Row
元素的 height
约束将是 Text
的最大 minIntrinsicHeight
。Divider
随后会将 height
扩展到由 Row
给定的 height
约束。
自定义布局中的 Intrinsics
创建自定义 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 阶段