Jetpack Compose - DrawModifier (十三)

Posted bug樱樱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jetpack Compose - DrawModifier (十三)相关的知识,希望对你有一定的参考价值。

初识DrawModifier

先看下面这段代码

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

应该知道这个黄色的方块,最终的大小应该是10dp,为啥? 因为background 始终都是会用到他右边的尺寸大小

可以看下这个background 实际上就是一个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 是在什么时候影响布局的吧

这个toWrap,上一节我们介绍过,本质上就是一层层嵌套的ModifierLayoutNode,是一个LayoutNodeWrapper的对象

再看下这个entities 是啥

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

可以看下他有几个子类

这个就很关键了,我们再切回去看看

首先这个DrawEntity就是我们刚才介绍过的,LayoutNodeEntitiy的子类,他包裹了我们的modifer,

看下第二个参数

这里可以知道 ,这第二个参数其实固定是0,虽然你看起来他是一个变量,但他本质上还是一个0

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

我们首先看一下这个entities是啥

可以看出来,这里 entities 就是一个长度为6的数组,

而这个数组里面 每一个位置上的元素都是固定的比如位置0 上放的永远就是drawmodifier,有人要问 如果有多个drawmodifer怎么办, 这里的数据结构其实和java中的hashmap非常向,这个数组中的每个元素 本质上就是一个链表,

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

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

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

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

首先看下draw方法 里面的layer,这里你就理解为图层的意思就可以了, 可以把一个视图分成几个独立的layer,这些layer 叠加以后展示出来的 就是你看到的view的效果

比如这里的alpha,底层也就是用的layer

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

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

而且这个我们看下这个performDraw函数方法里面 最终还是我们调用的我们前面介绍的draw方法,你可以理解为一个递归的调用逻辑

这里还应该要注意的是,在compose的体系中,所有组件底层都是用drawmodifier来实现的,比如text组件,image组件,等等

我们接着看,当有drawmodifier的时候 绘制的流程有什么变化

看上面的调用链 我们即可知道,绘制的过程其实就是在drawScope.draw 这个方法传递的 lambda,也就是那个block

这个lambda里面 最重要的就是当前这个modifier的draw方法了

这个draw方法是啥?其实就是那个接口啊

换个写法:

其实就是调用的我们写的drawWithContent这个函数的返回值了

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

看到这你应该能明白了,因为drawmodifier的调用 本质上是一个drawmodifier的链表的顺序调用,

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

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

再来详细看一下这个drawContent方法

这里就是判断一下 如果当前节点的drawModifer链表上还有节点 那继续绘制当前节点的drawmodifer 否则就去你包裹的子节点的drawModifer链表上去绘制

这么说好像有点绕了,我们换个说法

我们可以考虑一下 如果我们的界面是如下的结构

A包裹B包裹C,且每个节点都有自己的DrawModifier链表,那他实际上的绘制过程就可以概括为

注意了, 这里并不意味着, a1的内容一定会覆盖掉a2的内容,因为实际上 谁是谁的爹 这件事 是可以调整的

怎么理解这句话?

看下面这个例子

一个是先绘制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 ,为啥?

从右往左遍历的时候 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

作者:vivo祁同伟
链接:https://juejin.cn/post/7173941164020596749

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。


相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集

二、源码解析合集


三、开源框架合集


欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓

以上是关于Jetpack Compose - DrawModifier (十三)的主要内容,如果未能解决你的问题,请参考以下文章

Android Jetpack Compose学习—— Jetpack compose基础布局

Android Jetpack Compose学习—— Jetpack compose基础布局

Android Jetpack Compose学习—— Jetpack compose入门

Android Jetpack Compose学习—— Jetpack compose入门

jetpack compose 接收返回参数

什么是Jetpack Compose?带你走进Jetpack Compose~