在 Compose 中,您可以将多个修饰符链接在一起,以更改可组合项的外观和风格。这些修饰符链可能会影响传递给可组合项(用于定义宽度和高度边界)的约束条件。
本页将介绍链式修饰符如何影响约束条件,进而影响可组合项的测量和放置。
界面树中的修饰符
如需了解修饰符如何相互影响,最好直观了解它们在界面树中的显示方式,而界面树是在组合阶段生成的。如需了解详情,请参阅组合部分。
在界面树中,您可以将修饰符可视化为布局节点的封装容器节点:
向可组合项添加多个修饰符会创建修饰符链。当您链接多个修饰符时,每个修饰符节点都会封装链的其余部分和其中的布局节点。例如,当您链接 clip
和 size
修饰符时,clip
修饰符节点会封装 size
修饰符节点,而后者随后会封装 Image
布局节点。
在布局阶段,遍历树的算法将保持不变,但也会访问每个修饰符节点。这样一来,修饰符就可以更改其封装修饰符或布局节点的尺寸要求及位置。
如图 2 所示,Image
和 Text
可组合项的实现本身由封装单个布局节点的修饰符链组成。Row
和 Column
的实现只是描述如何布置其子项的布局节点。
总结:
- 修饰符用于封装单个修饰符或布局节点。
- 布局节点可以布置多个子节点。
以下部分介绍了如何使用此构思模型来推断修饰符链,以及它对可组合项的大小有何影响。
布局阶段中的约束条件
布局阶段会遵循一个三步算法来查找每个布局节点的宽度、高度和 x、y 坐标:
- 测量子节点:节点会测量其子节点(如果有)。
- 确定自己的大小:节点根据这些测量结果决定自己的大小。
- 放置子节点:每个子节点均相对于节点自身的位置进行放置。
Constraints
有助于在算法的前两个步骤中找到合适的节点大小。约束条件定义了节点宽度和高度的最小和最大边界。当节点确定其大小时,其测量大小应在此大小范围内。
限制条件的类型
限制条件可以是以下各项之一:
- 有边界:节点具有最大和最小宽度和高度。
- 无界限:节点不限大小。最大宽度和高度边界会设置为无穷大。
- 完全匹配:要求节点遵循确切的大小要求。最小和最大边界设置为相同的值。
- 组合:节点遵循上述限制条件类型的组合。例如,某个约束条件可以限制宽度,同时允许无限制的最大高度,或者设置确切宽度但提供有界限高度。
下一部分将介绍如何将这些约束条件从父项传递到子项。
约束如何从父项传递到子项
在布局阶段中的约束条件中所述的算法的第一步,约束条件会在界面树中从父项向下传递到子项。
当父节点测量其子节点时,它会为每个子节点提供这些限制,让子节点知道其允许的大小。然后,在确定自己的大小时,它也会遵循自己的父级传入的约束条件。
大体上讲,该算法的运作方式如下:
- 为了确定它实际想要占用的大小,界面树中的根节点会测量其子节点,并将相同的约束条件转发给其第一个子节点。
- 如果子项是不影响测量的修饰符,它会将约束条件转发给下一个修饰符。除非达到影响测量的修饰符,否则约束条件会按原样沿修饰符链向下传递。然后,系统会相应地调整约束条件的大小。
- 当到达的节点没有任何子节点(称为“叶节点”)时,它会根据传入的约束条件确定其大小,并将解析后的大小返回给其父节点。
- 父级会根据此子级的测量结果调整其约束条件,并使用这些调整后的约束条件调用其下一个子级。
- 测量完父节点的所有子节点后,父节点会确定自己的大小,并将其传达给自己的父节点。
- 这样,系统会优先遍历整个树。最后,所有节点确定其大小,测量步骤完成。
如需查看深入示例,请观看约束条件和修饰符顺序视频。
影响约束的修饰符
在上一部分中,您已了解某些修饰符可能会影响约束条件大小。以下部分介绍了影响约束的具体修饰符。
size
修饰符
size
修饰符用于声明内容的首选尺寸。
例如,以下界面树应通过 200dp
在 300dp
的容器中呈现。约束条件是有界限的,允许宽度介于 100dp
和 300dp
之间,高度介于 100dp
和 200dp
之间:
size
修饰符会调整传入的约束条件,以匹配传递给它的值。在此示例中,值为 150dp
:
如果宽度和高度小于最小约束条件边界或大于最大约束条件边界,则修饰符会尽可能匹配地匹配传递的约束条件,同时仍然遵守传入的约束条件:
请注意,链接多个 size
修饰符不起作用。第一个 size
修饰符将最小和最大约束设置为固定值。即使第二个尺寸修饰符请求更小或更大的尺寸,它仍然需要遵守传入的确切边界,因此它不会替换这些值:
requiredSize
修饰符
如果您需要节点来替换传入的约束条件,请使用 requiredSize
修饰符而非 size
。requiredSize
修饰符会替换传入的约束条件,并传递您指定为确切边界的大小。
将大小传回树时,子节点将以可用空间为中心:
width
和 height
修饰符
size
修饰符会调整约束条件的宽度和高度。您可以使用 width
修饰符设置固定宽度,但不决定高度。同样,使用 height
修饰符,您可以设置固定高度,但不决定宽度:
sizeIn
修饰符
借助 sizeIn
修饰符,您可以为宽度和高度设置确切的最小和最大约束。如果您需要对约束进行精细控制,请使用 sizeIn
修饰符。
示例
本部分显示并解释了几个带链式修饰符的代码段的输出。
Image( painterResource(R.drawable.hero), contentDescription = null, Modifier .fillMaxSize() .size(50.dp) )
以下代码段会生成以下输出:
fillMaxSize
修饰符会更改约束条件,将最小宽度和高度同时设置为最大值,即宽度为300dp
,高度为200dp
。- 虽然
size
修饰符想要使用大小为50dp
,但它仍需要遵循传入的最小约束。因此,size
修饰符还会按200
输出300
的确切约束范围,实际上会忽略size
修饰符中提供的值。 Image
遵循这些边界,并报告大小为300
x200
(沿树向上传递一层)。
Image( painterResource(R.drawable.hero), contentDescription = null, Modifier .fillMaxSize() .wrapContentSize() .size(50.dp) )
以下代码段会生成以下输出:
fillMaxSize
修饰符会调整约束,将最小宽度和高度设置为最大值,即宽度为300dp
,高度为200dp
。wrapContentSize
修饰符会重置最小约束。因此,虽然fillMaxSize
会生成固定约束条件,但wrapContentSize
会将其重置为有边界约束条件。下一个节点现在可以再次占据整个空间,或者小于整个空间。size
修饰符将约束条件设置为50
的最小和最大边界。Image
按50
解析为50
的大小,然后size
修饰符会转发该值。wrapContentSize
修饰符有一个特殊属性。它会获取它的子项,并将其放在传递给它的可用最小边界的中心。因此,它传递给父级的大小就等于传入它的最小边界。
通过仅组合三个修饰符,您可以为可组合项定义尺寸并将其居中放置在其父项中。
Image( painterResource(R.drawable.hero), contentDescription = null, Modifier .clip(CircleShape) .padding(10.dp) .size(100.dp) )
以下代码段会生成以下输出:
clip
修饰符不会更改约束条件。padding
修饰符会降低最大约束。size
修饰符将所有约束条件设置为100dp
。Image
遵循这些限制,并通过100dp
报告大小为100
。padding
修饰符会针对所有尺寸添加10dp
,因此它会将报告的宽度和高度增加20dp
。- 现在,在绘制阶段,
clip
修饰符通过120dp
对120
画布起作用。因此,它会创建一个相应大小的圆形遮罩。 - 然后,
padding
修饰符会在所有尺寸上10dp
插入其内容,因此会将画布尺寸降低至100
100dp
。 - 系统会在该画布中绘制
Image
。图像根据120dp
的原始圆圈进行裁剪,因此输出为非圆形结果。