用剪纸类比Android View的绘制流程

来源:互联网 发布:java框架和架构 源码 编辑:程序博客网 时间:2024/04/28 11:52

这个话题网上已有许多优秀的文章,但大部分都讲得比较严肃,本文打算用剪纸来类比,旨在帮助大家理解也方便记忆,本文尽量少提代码,免得想睡,只传达原理和思想。

首先请注意一个界面的所有View是用一棵树组织的,如:



View的绘制主要经过三个流程,分别是测量(measure),布局(layout),绘画(draw),以下我们逐个介绍。

我们需要一块布,代表画布,来吧:

值得注意的是其实Android中一个View树是共用一块画布的,有很多人都没有注意到这一点,有这块布之后就把它摊开,变成这样:


这块布先放这里,下面开始第一个流程——测量(measure),这个流程是从根view开始,每个view会问自己所有的子view的想占地多大,但会给个允许的最大值,这样一直递归下去,这个消息会一直传递到叶子节点。相当于父view是一张大纸,子view可以根据需要剪下一块,孙子再从儿子上再剪,如下图,其三个子view分别根据自己的需要剪一块下来:


假如父view的大小设置是WRAP_CONTENT,那他得根据子类大小计算自己的大小,就是这三个view的占地面积之和,如下图这样:


第一个流程就算完了,开始第二个流程——布局,这个流程就是ViewGroup安排自己的孩子坐落到哪里,在我们这里,就是把剪纸贴到哪里的问题,不同的ViewGroup安排自己孩子的方法不同,如LinearLayout是顺序的,而FrameLayout是分层放的,我们这里搞点个性,弄成三角恋型的算了,如下:


父类是通过调用子类的layout(l, t, l, r)方法来告诉子类它的坐位的,(其实这个layout()我觉得有前两个参数就够了,因为前一步已经确定大小了,不知道google设计四个参数的目的是什么)。这个流程就是这么简单的完成了。

第三个流程是绘画,这个流程,父view会通过调用子view的onDraw()方法传一个画布(canvas)给子view,子view可以在上面任意画东西,如位图,文字,圆饼/圆圈,矩形,直线等,爱怎么搞怎么搞,不过虽然整个view树用的是同一块画布,子view是画不到别的view的地盘的,因为父view此前就给canvas围一个小栅栏,是调用canvas的clip方法来实现的。在画布上画东西的时候,还可以定制画笔(Paint),比如笔的粗细啊,颜色啊,等等,当然自己也可以继承Paint类,实现一个奇怪的笔,比如用鸟屎写字,我这里就不示范了,为简单起见,我画成这样:


把刚刚这张白纸换成是透明的纸,而绘画是在画布上,可能更好理解的一点。

这个文章主要部分算完了。另外,解释一下invalidate()和requestLayout()的区别:

invalidate只会在触发对ondraw的调用,这是API说明原话:Invalidate the whole view. If the view is visible, onDraw() will be called at some point in the future. 

而requestLayout会触发ViewRootImpl里的performTraversals(),这个方法会根据需要决定是否执行三个完整流程,之前我看到一篇阅读量很大的文章说requestLayout只可能触发两个流程,不会触发onDraw,那是不正确的说法,其实根据上面的剪纸模型就可以推断出,如果你这块画布都变小了,或横的变成竖的啦,是肯定要擦除重画的。

关于performTraversals()本文不打算细分析了,网上很多这方面的文章,也可以看源代码。

0 0
原创粉丝点击