约束条件和修饰符顺序

在 Compose 中,您可以将多个修饰符串联在一起,以更改可组合项的外观和风格。这些修饰符链可能会影响传递的约束条件 可组合项,后者定义了宽度和高度边界。

本页介绍链接的修饰符如何影响约束条件,进而影响 可组合项的测量和放置。

界面树中的修饰符

为了了解修饰符如何相互影响,请直观地了解它们在界面树中的显示方式(界面树是在组合阶段生成的)。对于 如需了解详情,请参阅组合部分。

在界面树中,您可以将修饰符视为布局节点的封装容器节点:

可组合项和修饰符的代码,及其以界面树的形式呈现的视觉表示。
图 1. 在界面树中封装布局节点的修饰符。

向可组合项添加多个修饰符会创建一个修饰符链。时间 链接多个修饰符,每个修饰符节点都会封装链的其余部分 以及其中的布局节点。例如,当您链接 clipsize 修饰符时,clip 修饰符节点会封装 size 修饰符节点,然后 size 修饰符节点会封装 Image 布局节点。

在布局阶段,遍历树的算法保持不变,但系统也会访问每个修饰符节点。这样,修饰符就可以更改其封装的修饰符或布局节点的大小要求和位置。

如图 2 所示,ImageText 可组合项的实现 本身由封装单个布局节点的一系列修饰符组成。通过 RowColumn 的实现只是用来描述 布置自己的孩子

之前的树结构,但现在每个节点都只是一个简单的布局,有大量的修饰符将节点包裹在它周围。
图 2. 与图 1 相同的树结构,但在 以修饰符链的形式呈现的界面树。

总结:

  • 修饰符会封装单个修饰符或布局节点。
  • 布局节点可以布局多个子节点。

以下部分介绍了如何使用此心理模型推理修饰符串联及其对可组合项的大小有何影响。

布局阶段中的约束条件

布局阶段采用三步算法来查找每种布局 节点的宽度、高度以及 x、y 坐标:

  1. 测量子节点:节点会测量其子节点(如果有)。
  2. 确定自己的尺寸:节点根据这些测量结果确定自己的尺寸。
  3. 放置子节点:每个子节点都是相对于节点自身的节点放置的 排名。

Constraints 可帮助在算法的前两个步骤中为节点找到合适的大小。约束条件定义了 节点的宽度和高度。当节点确定其大小时,其测量到的大小 都应该在该尺寸范围内

限制条件的类型

限制条件可以是以下项之一:

  • 受限:节点具有宽度和高度上限和下限。
容器内不同大小的边界约束条件。
图 3. 边界约束条件。
  • 无界限:节点不受任何大小限制。最大宽度和高度边界设为无穷大。
将宽度和高度设置为无限的无边界约束条件。限制条件会延伸到容器之外。
图 4.无界限约束。
  • 完全匹配:要求节点遵循确切大小要求。最低 和最大边界设置为相同的值。
符合容器内确切尺寸要求的确切约束条件。
图 5. 精确约束条件。
  • 组合:节点遵循上述约束条件类型的组合。例如,约束条件可以限制宽度,同时允许无上限的最大高度,也可以设置确切宽度,但提供受限的高度。
两个容器,显示了边界约束条件和无边界约束条件以及确切宽度和高度的组合。
图 6.有界限约束条件和无界限约束条件以及精确宽度的组合 高度。

下一部分将介绍如何将这些约束从父级传递到 子节点。

如何将约束条件从父项传递给子项

布局阶段的约束条件中所述算法的第一个步骤中,约束条件会从界面树中的父项向下传递给子项。

当父节点测量其子节点时,它会向每个子节点提供这些约束条件,以告知它们允许的大小。然后,在确定自己的大小时,它还会遵循其父级传入的约束条件。

概括来讲,该算法的运作方式如下:

  1. 界面树中的根节点可以决定它实际占用的空间 测量其子项,并将相同的约束条件转发到其第一个子项。
  2. 如果子项是不影响测量的修饰符,则会转发 下一个修饰符的约束条件。除非遇到会影响衡量的修饰符,否则约束条件会按原样向下传递到修饰符链。然后,系统会相应地调整约束条件的大小。
  3. 到达没有任何子节点的节点时(称为“叶” 节点”),它会根据传入的约束条件来决定其大小,以及 将此解析后的尺寸返回给其父项。
  4. 父级根据这个子级的测量结果调整其约束条件,并且 并使用这些调整后的约束调用其下一个子级。
  5. 测量父级的所有子级后,父级节点会确定自己的大小,并将其告知自己的父级。
  6. 这样,系统会优先遍历整个树。最终,所有节点都确定了其大小,测量步骤也随之完成。

如需查看深入的示例,请参阅约束和修饰符顺序 视频。

影响限制条件的修饰符

在上一部分中,您已了解某些修饰符会影响约束条件 。以下部分介绍了会影响约束条件的具体修饰符。

size 修饰符

size 修饰符用于声明内容的首选尺寸。

例如,以下界面树应呈现在 300dp 的容器中。 上传者:200dp。约束条件是有边界的,允许宽度介于 100dp300dp,高度介于 100dp200dp 之间:

界面树的一部分,其中大小修饰符封装了布局节点,以及容器中大小修饰符设置的边界约束条件的表示法。
图 7. 界面树中的边界约束条件及其在容器中的表示法。

size 修饰符会调整传入的约束条件,以匹配传递给它的值。 在此示例中,该值为 150dp

与图 7 相同,但尺寸修饰符会调整传入约束条件,以匹配传递给它的值。
图 8. 将约束条件调整为 150dpsize 修饰符。

如果宽度和高度小于最小约束边界,或者 大于最大约束边界,则修饰符会匹配传递的 同时仍然遵循已传递的限制条件, 位置:

两个界面树及其在容器中的对应表示法。在第一个示例中,
  size 修饰符接受递增的约束条件;而尺寸修饰符会适应
  约束条件设置得尽可能大,导致约束条件填满容器。
图 9. size 修饰符尽可能贴近传递的约束条件 尽可能高。

请注意,串联多个 size 修饰符不起作用。前 size 修饰符将最小和最大约束条件设置为固定值。即使第二个大小修饰符请求的大小更小或更大,它仍需要遵循传入的确切边界,因此不会替换这些值:

界面树中由两个尺寸修饰符组成的链及其在容器中的表示法,
  即传入的第一个值而非第二个值的结果。
图 10. 由两个 size 修饰符组成的链,其中传递了第二个值 (50dp) 中的函数不会替换第一个值 (100dp)。

requiredSize 修饰符

如果您需要requiredSizesize 节点覆盖传入的约束条件。requiredSize 修饰符将替换 传入约束条件,并将您指定的尺寸作为确切边界进行传递。

当大小传回树时,子节点将在 可用空间:

size 和 requiredSize 修饰符链接在界面树中,以及相应的
  以容器的形式呈现requiredSize 修饰符约束条件会替换 size 修饰符约束条件。
图 11. requiredSize 修饰符会替换 size 修饰符。

widthheight 修饰符

size 修饰符可同时调整约束条件的宽度和高度。包含 width 修饰符,您可以设置固定宽度,但无需确定高度。 同样,使用 height 修饰符,您可以设置固定高度,但宽度不确定:

两个界面树,一个包含宽度修饰符及其容器表示法,另一个包含高度修饰符及其表示法。
图 12. width 修饰符和 height 修饰符设置固定宽度 和高度。

sizeIn 修饰符

借助 sizeIn 修饰符,您可以设置精确的最小和最大约束条件 指定宽度和高度如果您需要进行精细控制,请使用 sizeIn 修饰符

一个包含设置了最小和最大宽度和高度的 sizeIn 修饰符的界面树,以及其在容器中的表示形式。
图 13. 设置了 minWidthmaxWidthminHeightmaxHeightsizeIn 修饰符。

示例

本部分显示并解释了使用 修饰符。

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .size(50.dp)
)

此代码段会生成以下输出:

  • fillMaxSize 修饰符会更改约束条件,以便同时设置 将最小宽度和高度设置为最大值 - 宽 300dp200dp 高度。
  • 虽然 size 修饰符想要使用 50dp 的大小,它仍然需要 以遵守传入的最小约束。因此,size 修饰符还会通过 200 输出 300 的确切约束边界,从而有效地忽略 size 修饰符中提供的值。
  • Image 遵循这些边界,报告大小为 300 乘以 200, 一直传到树上。

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,因此它会增加 高度和宽度 x 20dp
    • 现在,在绘制阶段,clip 修饰符会按以下方式作用于 120 的画布: 120dp。因此,它会创建该大小的圆形遮罩
    • 然后,padding 修饰符会在所有尺寸上按 10dp 嵌入其内容,因此 将画布大小降低到 100 100dp
    • Image 会绘制在该画布中。图片会根据 120dp 的原始圆形进行剪裁,因此输出结果是非圆形。