初识DrawModifier

先看下面这段代码

Box(
    modifier = Modifier
        .requiredSize(50.dp)
        .background(Color.Yellow)
        .requiredSize(10.dp)
)

应该知道这个黄色的方块,终究的巨细应该是10dp,为啥? 由于background 一直都是会用到他右边的尺寸巨细

能够看下这个background 实际上便是一个DrawModifier

Jetpack Compose - DrawModifier (十三)

Jetpack Compose - DrawModifier (十三)

看一下 下面的写法:

Box(
    modifier = Modifier
        .background(Color.Red)
        .size(50.dp).drawWithContent {
        }
)

跑一下,能看出来 这是一个50dp巨细的赤色矩形

可是我假如略微改一下代码,变成下面这样的:

Box(
    modifier = Modifier
        .size(50.dp).drawWithContent {
        }.background(Color.Red)
)

你就会发现这个赤色的矩形消失了

再改一下:

Box(
    modifier = Modifier
        .size(50.dp).drawWithContent {
            drawContent()
        }.background(Color.Red)
)

你会发现 这个赤色矩形又回来了,为什么drawContent办法不调用,结果就会犯错呢?

带着上述的疑问, 咱们跟一下DrawModifier的代码,看看 他在compose中的制作流程中,起到了一些什么作用,为什么会造成上述比方中的现象

注意这篇文章需求 LayoutModifier 作为基础

源码分析

看下DrawModifer 是在什么时分影响布局的吧

Jetpack Compose - DrawModifier (十三)

Jetpack Compose - DrawModifier (十三)

这个toWrap,上一节咱们介绍过,本质上便是一层层嵌套的ModifierLayoutNode,是一个LayoutNodeWrapper的目标

再看下这个entities 是啥

Jetpack Compose - DrawModifier (十三)

Jetpack Compose - DrawModifier (十三)

这个LayoutNodeEntitiy 里边还包裹了一个Modifier,

能够看下他有几个子类

Jetpack Compose - DrawModifier (十三)

这个就很要害了,咱们再切回去看看

Jetpack Compose - DrawModifier (十三)

首要这个DrawEntity便是咱们方才介绍过的,LayoutNodeEntitiy的子类,他包裹了咱们的modifer,

看下第二个参数

Jetpack Compose - DrawModifier (十三)

这儿能够知道 ,这第二个参数其实固定是0,虽然你看起来他是一个变量,但他本质上仍是一个0

再看下这个add函数,一个简略的链表操作

Jetpack Compose - DrawModifier (十三)

咱们首要看一下这个entities是啥

Jetpack Compose - DrawModifier (十三)

Jetpack Compose - DrawModifier (十三)

能够看出来,这儿 entities 便是一个长度为6的数组

而这个数组里边 每一个方位上的元素都是固定的比方方位0 上放的永久便是drawmodifier,有人要问 假如有多个drawmodifer怎样办, 这儿的数据结构其实和java中的hashmap非常向,这个数组中的每个元素 本质上便是一个链表,

举个比方,假设有个3个drawmodifer 组成了这个链表 LayoutNodeEntity(drawmodifer3)->LayoutNodeEntity(drawmodifer2)>LayoutNodeEntity(drawmodifer1)

然后这个链表就放到了 这个enties的 第0个方位上,仅此而已

搞清楚这个数据结构 其他地方就不难理解了,

下面就持续看下 draw办法 里边干了啥,是如何被DrawModifier影响的

Jetpack Compose - DrawModifier (十三)

首要看下draw办法 里边的layer,这儿你就理解为图层的意思就能够了, 能够把一个视图分成几个独立的layer,这些layer 叠加以后展现出来的 便是你看到的view的作用

比方这儿的alpha,底层也便是用的layer

Jetpack Compose - DrawModifier (十三)

接着看,其实下面这个姓名很长的draw函数 在有了前面的分析基础上,就很好理解了,便是去entities这个数组里边 取drawmodifer方位上的链表, 然后看一下这个链表有没有值,有值就 把内容和drawmodifier一起制作 没有值,那就只制作内容

Jetpack Compose - DrawModifier (十三)

咱们首要看下这个performDraw函数,这个函数是会在 没有drawModifier时分被调用,这儿的wrapped 是啥? 前面LayoutModifier的文章里介绍过的,A 包裹B,这个B 便是wrapped, 那为什么 这儿wrapped还有个判空的问号? 由于最里层的Node节点 明显是没有包裹任何东西的

Jetpack Compose - DrawModifier (十三)

并且这个咱们看下这个performDraw函数办法里边 终究仍是咱们调用的咱们前面介绍的draw办法,你能够理解为一个递归的调用逻辑

这儿还应该要注意的是,在compose的体系中,所有组件底层都是用drawmodifier来完成的,比方text组件,image组件,等等

咱们接着看,当有drawmodifier的时分 制作的流程有什么变化

Jetpack Compose - DrawModifier (十三)

Jetpack Compose - DrawModifier (十三)

Jetpack Compose - DrawModifier (十三)

看上面的调用链 咱们即可知道,制作的进程其实便是在drawScope.draw 这个办法传递的 lambda,也便是那个block

这个lambda里边 最重要的便是当时这个modifier的draw办法了

Jetpack Compose - DrawModifier (十三)

这个draw办法是啥?其实便是那个接口啊

Jetpack Compose - DrawModifier (十三)

Jetpack Compose - DrawModifier (十三)

换个写法:

其实便是调用的咱们写的drawWithContent这个函数的回来值了

Jetpack Compose - DrawModifier (十三)

这儿有人会问,这个drawConent办法不调用的话,界面就展现不出来 这是为啥?

Jetpack Compose - DrawModifier (十三)

看到这你应该能理解了,由于drawmodifier的调用 本质上是一个drawmodifier的链表的顺序调用,

而完成这个顺序调用的便是这个drawContent办法, 你假如不去调用这个drawContent办法 那就意味着

你这个组件的制作 只制作了你的head node部分,而剩余的部分你都没有制作。。。

再来具体看一下这个drawContent办法

Jetpack Compose - DrawModifier (十三)

这儿便是判别一下 假如当时节点的drawModifer链表上还有节点 那持续制作当时节点的drawmodifer 否则就去你包裹的子节点的drawModifer链表上去制作

这么说如同有点绕了,咱们换个说法

咱们能够考虑一下 假如咱们的界面是如下的结构

Jetpack Compose - DrawModifier (十三)

A包裹B包裹C,且每个节点都有自己的DrawModifier链表,那他实际上的制作进程就能够归纳为

Jetpack Compose - DrawModifier (十三)

注意了, 这儿并不意味着, a1的内容一定会覆盖掉a2的内容,由于实际上 谁是谁的爹 这件事 是能够调整的

怎样理解这句话?

看下面这个比方

Jetpack Compose - DrawModifier (十三)

一个是先制作content 再制作一个圆形,那明显便是这个圆点会遮盖住content

反之,则content会遮盖住这个圆点

一些比方分析

Box(
    modifier = Modifier.background(Color.Red).background(Color.Blue).size(40.dp)
)

这个Box 会显现什么色彩? 明显是蓝色, 由于有了第二小节的分析 咱们知道,

先制作了赤色背景的drawmodifer,然后再制作了蓝色背景的Modifer, 左边包裹着右边 蓝色天然就覆盖了赤色,所以终究是蓝色

再看下这个比方:

Box(
    modifier = Modifier.requiredSize(80.dp).background(Color.Blue).requiredSize(10.dp)
)

这个蓝色的方块终究有多大?,答案是10dp ,为啥?

Jetpack Compose - DrawModifier (十三)

从右往左遍历的时分 DrawModifer是和toWrap来绑定在一起的, 到这个比方中便是 遍历到了 蓝色方块的DrawModifier的时分 他就和 toWrap绑定在一起了,这个toWrap 明显便是那个10dp巨细的layoutModifer

简而言之, drawModifier的制作巨细总是跟从着 他右边的layoutModifier

再看最后一个比方

Box(
    modifier = Modifier.size(40.dp).padding(19.dp).background(Color.Blue)
)

这儿蓝色的方块有多大? 应该是一个size为2的 方块对吧,

可是你要如何得出这个size为2的定论?

前面介绍过 drawModifer也便是这个比方中的background 的巨细是跟从他右边的layoutModifer的

可是这个比方中右边没有了? 既然右边没有了 为啥终究巨细是2

回忆上一个文章中layoutmodifer的常识,这儿最外层是一个40dp的size,然后包裹着一个padding为19的layout,天然剩余的空间就只有40-19*2=2了, 所以终究的blue 的方块巨细便是2