深入Jetpack Compose——布局原理与自定义布局(二)
在上一篇文章深入Jetpack Compose——布局原理与自定义布局(一) - 掘金 (juejin.cn) 中,我们大致了解了Layout过程并简单实现了两个自定义布局。本次让我们将目光转向Modifier和固有特性测量
本文部分参考自Android官方视频:Deep dive into Jetpack Compose layouts
Modifier
本质
关于Modifier的本质,RugerMc
大佬在图解 Modifier 实现原理 ,竟然如此简单这篇文章中已经解释地非常清楚了,我就不画蛇添足了。不过为了后续行文方便,我还是在此简单说几点:
- Modifier 是个接口,包含三个直接实现类或接口:
伴生对象 Modifier
、内部子接口Modifier.Element
和CombinedModifier
。 伴生对象Modifier
是日常使用最多的,后面两者均为内部实现,实际开发中无需关注Modifier.xxx()
方法实际上会创建一个Modifier
接口的实现类的实例。如Modifier.size()
会创建SizeModifer
实例
1 |
|
Modifier.xxx().yyy().zzz()
实际上会创建一个Modifier链,内部顺序遵循 xxx -> yyy -> zzz ,由CombinedModifier
连接。Modifie接口
提供了foldIn
/foldOut
方法允许我们顺序
/逆序
遍历到每个Modifier这里借上面文章中的一张图来说明:
我们可以简单遍历一下看看,对于下面的例子:
1 |
|
它的输出为:
1 | 0 -> androidx.compose.foundation.layout.SizeModifier@78000000 |
作用
接下来,我们看看Modifier是怎么在布局中起作用的
先看一个例子
1 |
|
它实际显示的效果如下
我们来逐步看看这到底是怎么发生的。这里我们选择子元素,也就是那个小一点的蓝色Box,来看看它的measure和place过程。
首先是measure。父元素明确了自身大小为200*300,该大小也就是子元素能占据的最大空间。因此
初始:初始约束 w:0-200, h:0-300
fillMaxSize():占据最大空间,约束的
min
值更改为与max
相同,即 w:200-200, h:300-300wrapContentSize():适应内容大小,约束的
min
值重新变回了0,即 w:0-200, h:0-300size():指定了精准大小。约束变为 w:50-50, h:50-50
background():对大小约束无影响
最后,在Modifier
的一顿操作之下,Box会收到一个 w:50-50, h:50-50 的约束。到这里走过的状态如下:
接下来,Box内部的Layout
微件执行measure方法得到了自己的大小:50*50。这个大小反向传回到Modifier链的最后一项,并开始place。接下来:
- background():此处略过
- size(50.dp):测得自己的大小:50*50,并据此创建自己的位置指令
- wrapContentSize():测得自己的大小:200*300,并知道自己的子元素大小50*50,且居中放置。据此创建自己的位置指令。
- fillMaxSize():解析自己的大小和位置
这个过程很类似于Layout
微件,区别就是每个Modifier只有一个子元素(也就是Modifier链上的下一个元素)。事实上,如果看代码,你也很容易感受到二者的相似之处
拿wrapContentSize
修饰符的代码举例,其实现类WrapContentModifier
的measure
方法如下
1 | fun MeasureScope.measure( |
怎么样,是不是很相似?
后续
关于Modifier我们就先看这些。下一篇,我们将接触固有特性测量
这一特性,并改进我们在第一篇文章中实现的纵向布局。
本文所有代码见:此处