约束条件和修饰符顺序

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

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

界面树中的修饰符

要了解修饰符如何相互影响,最好先直观地了解 它们会显示在组合阶段生成的界面树中。对于 如需了解详情,请参阅组合部分。

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

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

向可组合项添加多个修饰符,即可创建一系列修饰符。时间 链接多个修饰符,每个修饰符节点都会封装链的其余部分 以及其中的布局节点。例如,如果您将 clipsize 修饰符,clip 修饰符节点会封装 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. size 修饰符将约束条件调整为 150dp

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

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

请注意,链接多个 size 修饰符不起作用。前 size 修饰符将最小和最大约束条件设置为固定值。即使 第二个尺寸修饰符请求更小或更大的尺寸,它仍然需要 遵循传入的确切上下限,因此不会替换以下值:

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

requiredSize 修饰符

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

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

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

widthheight 修饰符

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

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

sizeIn 修饰符

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

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

示例

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

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

此代码段生成以下输出:

  • fillMaxSize 修饰符会更改约束条件,以便同时设置 将最小宽度和高度设置为最大值 - 宽 300dp200dp 高度。
  • 虽然 size 修饰符想要使用 50dp 的大小,它仍然需要 以遵守传入的最小约束。因此,size 修饰符将 还会输出 300 乘以 200 的精确约束边界,实际上 并忽略 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 遵循这些限制并报告大小为 100 100dp
    • padding 修饰符会针对所有尺寸添加 10dp,因此它会增加 高度和宽度 x 20dp
    • 现在,在绘制阶段,clip 修饰符会按以下方式作用于 120 的画布: 120dp。因此,它会创建该大小的圆形遮罩
    • 然后,padding 修饰符会在所有尺寸上按 10dp 嵌入其内容,因此 将画布大小降低到 100 100dp
    • 系统会在该画布中绘制 Image。图片会根据 120dp 的原始圆圈,因此输出是非舍入结果。