1.View绘制的流程框架
view的绘制是从上往下一层层迭代下来。DecorView --> ViewGroup( --> ViewGroup) --> View,按照这个流程往下,依次measure(测量),layout(布局),draw(绘制)。
二、Measure流程
调用measure()方法,进行一些逻辑处理,然后调用onMeasure()方法,在其中调用setMeasuredDimension()设置View的宽高信息,完成View的测量操作。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
如果有widthMeasureSpec,heightMeasureSpec,通过一定的处理(可以重写,自定义处理步骤),从中获取View的宽/高,调用setMeasuredDimension(),指定View的宽高,完成测量的工作。
MeasureSpec的确定
MeasureSpec释义:
MeasureSpec由两部分组成,一部分是测量模式,另一部分是测量的尺寸的大小。
Mode模式的分类:
UNSPECIFIED:不对View进行任何限制,要多大给多大,一般用于系统内部。
EXACTLY:对应LayoutParams中的match_parent和具体数值两种模式。检测到View所需的精确大小,这时候View的最终大小就是SpecSize所指定的值。
AT_MOST:对应LayoutParams中的wrap_content。View的大小不能大于父容器的大小。
MeasureSpec的确定
对于DecorView,其确定是通过屏幕的大小,和自身的布局参数LayoutParams。这部分很简单,根据LayoutParams的布局格局(match_parent,wrap_content,或指定大小),将自身大小,和屏幕大小相比,设置一个不超过屏幕大小的宽高,以及对应模式。对于其他View(包括ViewGroup),其确定是通过父布局的MeasureSpec和自身的布局参数LayoutParams。
View的测量流程:
三、Layout流程
测量完View大小后,就需要将View布局在Window中,View的布局主要通过上下左右四个点来确定的。
其中布局也是自上而下,不同的是ViewGroup先在layout()中确定自己的布局,然后在onLayout()方法中再调用子View的layout()方法,让子View布局。在Measure过程中,ViewGroup一般是先测量子View的大小,然后再确定自身的大小。
如果当前View就是一个单一的View,那么没有子View,就不需要实现onLayout方法。如果当前View是一个ViewGroup,就需要实现onLayout方法,该方法的实现与自定义ViewGroup时其特性相关,必须自己实现。由此便完成了一层层的布局工作。
View的布局流程:
四、Draw过程
View的绘制过程遵循如以下几步。
- a.绘制背景 background.draw(canvas);
- b.绘制自己(onDraw)
- c.绘制Children(dispatchDraw)
- d.绘制装饰 (onDrawScrollBar)
从源码中可以清楚地看出绘制的顺序。
无论是ViewGroup还是单一的View,都需要实现整套流程,不同的是,在ViewGroup中,实现了disPatchDraw(),而在单一子View中不需要实现该方法。自定义View一般要重写onDraw()方法,在其中绘制不同的样式。
view绘制流程:
五、总结
从View的测量、布局和绘制的原理来看,要实现自定义View,根据自定义的View的种类不同,可能分别要定义不同的方法。但是这些方法不外乎:onMeasure()方法,onLayout()方法,onDraw()方法。
onMeasure():单一View,一般重写此方法,针对wrap_content情况规定View默认的大小值,避免match_parent情况一致。ViewGroup,若不重写就会执行和单子View中相同的逻辑,不会测量子View。一般会重写onMeasure()方法,循环测量子View。
onLayout():单一View,不需要实现该方法。ViewGroup必须实现,该方法是个抽象方法,实现方法,来对子View进行布局。
onDraw(): 无论单一View,或者ViewGroup都需要实现该方法,因其是个空方法。