Compose 有一项规则,即,子项只能测量一次,测量两次就会引发运行时异常。但是,有时需要先收集一些关于子项的信息,然后再测量子项。
借助固有特性,您可以先查询子项,然后再进行实际测量。
对于可组合项,您可以查询其 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,并且文本是在单行中绘制的。
固有特性的实际运用
您可以创建一个可组合项,该可组合项在屏幕上显示两个用分隔线隔开的文本:
为此,请使用一个 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 的高度按如下方式确定:
Row可组合项的minIntrinsicHeight是其子项的最大minIntrinsicHeight。Divider元素的minIntrinsicHeight为 0,因为如果没有给出约束条件,它不会占用任何空间。TextminIntrinsicHeight是特定width的文本。- 因此,
Row元素的height约束条件将成为Text的最大minIntrinsicHeight。 - 然后,
Divider将其height扩展到Row给定的height限制。
自定义布局中的固有特性
创建自定义 Layout 或 layout 修饰符时,系统会根据近似值自动计算固有测量结果。因此,计算结果可能并不适用于所有布局。这些
API 提供了替换这些默认值的选项。
若要指定自定义 Layout 的固有特性测量,请在创建该布局时替换
minIntrinsicWidth、minIntrinsicHeight、maxIntrinsicWidth 和
maxIntrinsicHeight 的 MeasurePolicy。
@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 的阶段