MAD 技能:Compose 布局 和 修饰符 的第 2 集
在之前的 MAD 技能文章 中,您了解了开箱即用的 API,即 Jetpack Compose 提供的用于编写精美 app 的功能。在本文中,我们将创建一个思维模型,了解这些 API 如何将数据实际地转换为 UI。
您也可以将本文作为 MAD 技能视频观看:youtu.be/0yK7KoruhSM
由于 Compose 是一个声明式工具箱,我们在基本层面上知道它将数据转换为 UI。此转换过程中的 三个阶段 是:
- 组合: 显示什么
- 布局: 放在哪里
- 绘制: 如何渲染它
这三个阶段是逐一执行的:
三个阶段
三个阶段
在 组合阶段,Compose 运行时会执行您的可组合函数。它输出代表您的 UI 的树数据结构。此 UI 树由布局节点组成。这些布局节点一起持有完成下一阶段所需的所有信息。
Composition(组合) 阶段执行可组合函数并创建代表您的 UI 的树。
然后,在布局阶段,树中的每个元素测量其子元素(如果有)并将它们放置在可用的 2D 空间中:
布局阶段,测量每个布局节点,并将其放置在 UI 树中。
最后,在 绘制阶段,树中的每个节点都在屏幕上绘制其像素:
绘制阶段,在屏幕上绘制像素。
组合阶段
让我们放大并只关注屏幕的底部,在这里您可以看到文章的作者、发表日期和阅读时间:
在组合阶段,我们将可组合函数转换为 UI 树。 由于我们只查看 author 元素,我们可以放大我们的代码和 UI 树的一个子部分:
在这种情况下,我们代码中的每个可组合函数都映射到 UI 树中的单个布局节点。这是一个非常简单的示例,但您的可组合项可以包含逻辑和控制流,从而在给定不同状态的情况下生成不同的树。
布局阶段
当我们进入布局阶段时,我们使用这个 UI 树作为输入。布局节点的集合包含最终决定每个节点在 2D 空间中的大小和位置所需的 所有信息。
在布局阶段,使用以下 3 步算法遍历树:
- 测量子节点: 一个节点会测量它的子节点,如果有的话。
- 决定自己的大小: 基于这些测量,节点决定自己的大小。
- 放置子节点: 每个子节点都相对于节点自身的位置进行放置。
在该阶段结束时,每个布局节点都将分配一个宽度和高度,以及一个应该绘制的x、y 坐标。
因此,对于我们的可组合项,这将按如下方式工作:
Row测量其子项.- 首先,测量
Image。它没有任何子项,因此它决定自己的大小并将其报告回Row。 - 其次,测量
Column。它需要先测量自己的子项。 - 第一个
Text被测量。它没有任何子项,因此它决定自己的大小并将其报告回Column。 - 第二个
Text被测量。它没有任何子项,因此它决定自己的大小并将其报告回Column。 Column使用子测量值来决定自己的大小。它使用最大子宽度及其子项的高度之和。Column将其子项放置在相对于自身的位置,将它们垂直放置在彼此下方。Row使用子尺寸来决定自己的尺寸。它使用最大子高度和子宽度的总和。然后它放置它的子项。
这里的一个关键点是我们只访问了每个节点一次。通过UI树的一次遍历,我们就可以测量和放置所有节点。这对性能来说是极好的。当树中节点的数量增加时,遍历它所花费的时间以线性方式增加。相比之下,如果我们多次访问每个节点,遍历时间将呈指数级增加。
绘制阶段
既然我们知道了所有布局节点的大小和x,y坐标,我们就可以继续绘制阶段了。从上到下再次遍历树,每个节点依次在屏幕上绘制自己。因此,在我们的例子中,首先 Row 将绘制它可能具有的任何内容,例如背景色。然后 Image 将绘制自己,然后是 Column,然后是第一个和第二个 Text:
修饰符
太棒了! 我们已经了解了如何为我们的可组合项执行这三个阶段。但我们抄了些近道儿。
如果我们回到组合阶段,我们说过我们执行代码并构建 UI 树。
但仔细观察代码,我们可以看到它实际上使用了 modifiers(修饰符) 来改变一些可组合项的外观。在我们的 UI 树中,我们可以将这些可视化为布局节点的包装节点:
当我们链接多个修饰符时,每个修饰符节点包裹链的其余部分和其中的布局节点。 例如,当我们链接一个 clip 和一个 size 修饰符时,clip 修饰符节点包裹 size 修饰符节点,然后包裹 Image 布局节点。
在布局阶段,我们用来遍历树的算法保持不变,但每个修饰符节点也会被访问。这样,修饰符可以更改其包裹的 修饰符 或 布局节点 的 大小要求 和 位置。
现在,有趣的是,如果我们看一下 Image 可组合项的实现,我们实际上可以看到它本身由包裹单个布局节点的修饰符链组成。类似地,Text 可组合项也是通过包含布局节点的修饰符链实现的。最后,Row 和 Column 的实现只是描述如何布置其子节点的布局节点:
一路向下都是修饰符!
我们将在稍后的博文中回到这一点,但现在最好将修饰符视为包裹单个修饰符或布局节点,而布局节点可以布局多个子节点 .
总结
那么,有了这个思维模型,您现在可以更好地理解 Compose 的不同阶段是如何工作的。
在下一篇文章中,我们将更深入地探讨布局阶段,并学习推理 布局 和 修饰符 究竟如何影响子元素的测量和放置。
这篇博文是系列博文的一部分:
第 1 集:Compose 布局和修饰符的基础知识
第 2 集:Compose 的各个阶段
第 3 集:约束和修饰符顺序
第 4 集:高级布局概念