View视图绘制的过程原理

来源:互联网 发布:json汉字 编辑:程序博客网 时间:2024/06/05 23:48

View视图的绘制需要搞清楚两个问题,一个是从哪里开始绘制,一个是怎么绘制。

从哪里开始绘制?
我们在使用Activity的时候,都会调用setContentView来设置布局文件,视图的绘制就是从这个方法中开始的。
当然,我们调用invalid方法时,也会对View进行重新的绘制。

怎么绘制的?
在我们的Activity中调用了setContentView之后,会转而执行PhoneWindow的setContentView,在这个方法里面 会判断我们存放内容的ViewGroup(这个ViewGroup可以是DecorView也可以是DecorView的子View)是否存在。不存在的 话则会创建一个DecorView出来,并且会创建出相应的窗体风格,存在的话则会删除原先ViewGroup上面已有的View,接着会调用 LayoutInflater的inflate方法以pull解析的方式将当前布局文件中存在的View通过addView的方式添加到 ViewGroup上面来,接着在addView方法里面就会执行我们常见的invalidate方法了,这个方法不只是在View视图绘制的过程中经常 用到,其实动画的实现原理也是不断的调用这个方法来实现视图不断重绘的,执行这个方法的时候会调用他的父View的invalidateChild方法, 这个方法是属于ViewParent的,ViewGroup以及ViewRootImpl中都对他进行了实现,invalidateChild里 面主要做的事就是通过do while循环一层一层计算出当前View的四个点所对应的矩阵在ViewRoot中所对应的位置,那么有了这个矩阵的位置之后最终都会执行到 ViewRootImpl的invalidateChildInParent方法,执行这个方法的时候首先会检查当前线程是不是主线程,因为我们要开始准 备更新UI了,不是主线程的话是不允许更新UI的,接着就会执行scheduleTraversals方法了,这个方法会通过handler来执行 doTraversal方法,在这个方法里面就见到了我们平常所熟悉的View视图绘制的起点方法performTraversals了;

绘制的流程:

大体上讲View的绘制经历了Measure测量、Layout布局以及Draw绘制三个过程,具体来讲是从 ViewRootImpl的performTraversals方法开始。

首先执行的将是performMeasure方法,这个方法里面会传入两个 MeasureSpec类型的参数,他在很大程度上决定了View的尺寸规格,对于DecorView来说宽高的MeasureSpec值的获取与窗口尺 寸以及自身的LayoutParams有关,对于普通View来说其宽高的MeasureSpec值的获取由父容器以及自身的LayoutParams属 性共同决定,在performMeasure里面会执行measure方法,在measure方法里面会执行onMeasure方法,到这里 Measure测量过程对View与ViewGroup来说是没有区别的,但是从onMeasure开始两者有差别了,因为View本身已经不存在子 View了,所以他onMeasure方法将执行setMeasuredDimension方法,该方法会设置View的测量值,但是对于 ViewGroup来说,因为它里面还存在着子View,那么我们就需要继续测量它里面的子View了,调用的方法是measureChild方法,该方 法内部又会执行measure方法,而measure方法转而又会执行onMeasure方法,这样不断的递归进行下去,知道整个View树测量结束,这 样performMeasure方法执行结束了;

接着便是执行performLayout方法了,performMeasure只是测量出View树中 View的大小了,但是还不知道View的位置,所以也就出现了performLayout方法了,performLayout方法首先会执行 layout方法,以确定View自身的位置,如果当前View是ViewGroup的话,则会执行onLayout方法。在onLayout方法里面又 会递归的执行layout方法,直到当前遍历到的View不再是ViewGroup为止,这样整个layout布局过程就结束了;在View树中View 的大小以及位置都确定之后。

接下来就是真正的绘制View显示在界面的过程了,该过程首先从performDraw方法开始,performDraw方法 首先执行draw方法,在draw方法中首先绘制背景、接着调用onDraw方法绘制自己,如果当前View是ViewGroup的话,还要调用 dispatchDraw方法绘制当前ViewGroup的子View,而dispatchDraw方法里面实际上是通过drawChild方法间接调用 draw方法形成递归绘制整个View树,直到当前View不再是ViewGroup为止,这样整个View的绘制过程就结束了;

这里写图片描述

原创粉丝点击