Compose把数据转化为UI的三个阶段

本文根据自己的理解翻译自 MAD Skills Compose Layout and Modifier 系列文章的第二篇 Compose phases ,适合有Compose基础的同学阅读,另外建议有英语基础的同学直接看原文哈,附上原文链接

Compose作为一个声明式UI框架,我们知道本质上就是把数据转化为UI。这个转化可以细分为三个阶段:

  1. 组合:要显示什么东西
  2. 布局:怎么摆放
  3. 绘制:怎么渲染

这三个阶段按序进行

三个阶段

在组合阶段里, Compose 在运行时执行 Composable 函数转化为一个个 layout node, 使用多叉树的数据结构组织起来输出一个UI树,而所有的 layout node 包含了所有下一阶段需要的信息。

然后在布局阶段里,多叉树的所有有子节点的节点都测量他们的子节点,然后在一个二维空间里进行摆放:

最后在绘制阶段,所有节点各自绘制自己在屏幕位置的像素:

组合阶段

现在我们聚焦屏幕底部那部分UI,那里显示着文章的作者、发布日期和阅读所需时间:

组合阶段期间,我们把 Composable 函数转化成UI树。我们只看作者这部分元素,这样可以缩小我们关注的代码和UI树范围:

在这个例子里,每个 Composable 函数都会映射成UI树的 layout node 。这是一个很简单的例子,事实上 Composable 可以包含逻辑和控制流(if else, when...),在不同的状态下产生不同的UI树。

布局阶段

在布局阶段里,我们会使用组合阶段时生成的UI树。储存 layout node 的容器包含所有布局需要的尺寸、位置信息。

当布局阶段进行时,UI树会被遍历,每个 layout node 的处理又可以细分成3步

  1. 如果存在子 layout node ,则测量子 layout node
  2. 测量完子 layout node 后,开始决定自身的尺寸
  3. 根据子 layout node 的尺寸摆放子 layout node

在最后一步里,每个 layout node 会有指定的宽、高以及左上角的 x, y 轴坐标,用作之后的绘制范围与位置

对于我们的 Composable,会如下工作

  1. Row 测量它的子 Composable
  2. 首先 Image 会被测量,由于它没有子 Composable,它只需要决定自己的尺寸然后报告给 Row
  3. 然后 Column 会被测量,它需要测量自己的子 Composable 先
  4. Column 里的第一个 Text 先被测量,类似上面的 Image,由于它没有子 Composable,它只需要决定自己的尺寸然后报告给 Column
  5. 同上,紧接着 Column 里的第二个 Text 被测量
  6. Column 在所有子 Composable 测量好后开始根据子 Composable 的尺寸决定自己的尺寸,其中宽度取子 Composable 里宽度最大的,高度取子 Composable 的高度之和
  7. Column 将它所有子 Composable 相对自身进行摆放,将他们垂直放置在彼此下方
  8. 自此 Row 所有的子 Composable 测量完毕,也开始决定自身的尺寸,其中宽度取子 Composable 的宽度之和,高度取子 Composable 里高度最大的。
  9. Row 将它所有子 Composable 相对自身进行摆放,将他们水平放置在彼此右边

上面有一个关键细节是每个 layout node 我们只遍历一次 。通过一次单向的遍历(自底向上)我们就可以测量和摆放好所有的节点。这一点有利于布局的性能表现。随着UI变得复杂 layout node 越来越多,布局的所花费的时间也随 layout node 数量线性增长。相反,如果我们每个节点都多次遍历,布局的所花费的时间也随 layout node 数量指数增长。(View:你直接报我身份证得了)

绘制阶段

经过前面的两个阶段,我们知道了 layout node 的尺寸和左上角的 x, y 坐标,之后就进入到绘制阶段。同样地,UI树会自顶向下地遍历,每个节点依次在屏幕上绘制自身。以我们刚刚举的例子来说,首先Row会绘制它自己的内容如背景。然后 Image 绘制自身,再之后到 Column,Column 的第1个 Text,Column 的第2个 Text:

Modifier

好极了,现在我们已经知道了 Composable 三个阶段是如何进行的了,但是我们略过了一些细节。

回看组合阶段,我们说执行 Composable 函数来构建UI树。

但仔细看代码,可以看到我们是可以使用一些 modifiers 来改变 Composable 的外观的。下图中我们可视化地把那些 modifiers 包在 Composable 上:

当我们链式调用多个 modifier 方法的时候,每个 modifier node 都会层层嵌套地把其他 modifier 和 layout node 包起来。举例,当我们调用 clip 和 size 这两个 modifier 后,clip modifier node 会把size modifier node 包起来,而 size modifier node又把 Image 对应的 layout node 包了起来。

在布局阶段,遍历UI树的方式和上文分析的一样,但是所有的 modifier node 都会被访问。因此,modifier 是可以影响一个 layout node 的尺寸要求和摆放位置的。

有趣的是,如果我们去看一下 Image 的源码,我们发现它其实只是一个包含多个 modifier 链式调用的 layout node,Text 也是如此。而 Row 和 Column 的实现则是一个实现了如何摆放子 Composable 的layout node:

在后面的文章我们会再次回顾到这些,现在我们需要好好地消化理解一下:一个 Modifier 可以包着另一个 Modiifer 或 Layout node; 一个 Layout node 可以摆放多个子 Layout node.

结语

有了上文建立的心智模型后,你应该可以对Compose在三个阶段里是如何运作的有了更进一步的理解。

下一篇文章我们会对布局阶段稍微深入一点,理解布局和Modifier是如何确切地影响子node的测量和摆放的。

相关推荐
2501_916008892 分钟前
uni-app iOS 日志与崩溃分析全流程 多工具协作的实战指南
android·ios·小程序·https·uni-app·iphone·webview
文 丰5 分钟前
【AndroidStudio】官网下载免安装版,AndroidStudio压缩版的配置和使用
android
WillWolf_Wang6 分钟前
Linux 编译 Android 版 QGroundControl 软件并运行到手机上
android·linux·智能手机
fatiaozhang952710 分钟前
数码视讯TR100-OTT-G1_国科GK6323_安卓9_广东联通原机修改-TTL烧录包-可救砖
android·xml·电视盒子·刷机固件·机顶盒刷机
撬动未来的支点11 分钟前
【Android】内核及子系统
android
2501_915921431 小时前
iOS混淆工具实战 在线教育直播类 App 的课程与互动安全防护
android·安全·ios·小程序·uni-app·iphone·webview
前行的小黑炭4 小时前
Android Flow的其他使用:stateIn和冷流(普通Flow)
android·kotlin
tran_sient4 小时前
【Android】制造一个ANR并进行简单分析
android·anr
前行的小黑炭4 小时前
Android Flow:你真的了解?在工作当中的运用~~通过光照例子来解释一下..
android·kotlin
tangweiguo030519875 小时前
极致效率:用 Copilot 加速你的 Android 开发
android·copilot