View的绘制机制
一、view树的绘制流程
mesure(是否重新计算视图大小)->layout(是否从新安置视图位置)->draw(是否需要重绘)
二、measure
mesure的测量是一个树的递归过程,重上到下有序进行遍历,根据父容器对子容器的测量规格和参数获取子容器的长宽高,然后把子容器的长宽高返回给父容器进行统一的测量。
1、ViewGroup.LayoutParams:就是指定视图宽高的参数
(1)指定一个确定的值;
(2)MATCH_PARENT:
(3)WRAP_CONTEXT;
2、MesureSpec:测量规格,代表一个32位的值,高两位代表SpecMode,低30位标识SpecSize,SpecMode是指测量模式,而specSize是指在某种测量模式下的规格大小。
UNSPECIFIED
父容器不对View有任何限制,要多大给多大,这种情况一般用于系统内部,表示一种测量的状态。
EXACTLY
父容器已经测量出View所需要的精确大小,这个时候View的最终大小就是SpecSize所指定的值。它对应于LayoutParams中的match_parent和具体的数值这两种模式。
AT_MOST
父容器指定了一个可用大小即SpecSize,View大小不能大于这个值,具体是什么值要看不同View的具体实现。它对应于LayoutParams中的Wrap_content
3、onMeasure:在之前的measure方法中获取了宽高的测量规格,并且传递到onMeasure方法中。onMeasure方法中获得计算的尺寸传给onMeasure中的setMeasureDimension方法。
4、setMeasureDimension:这是一个测量计算结束最终决定view的大小的方法,在重写onMeasure中这个方法必须要调用的,否则会出现异常。
三、Layout
跟measure一样,同样是跟图中的自上而下进行遍历,在这个过程中Layout方法会根据测量的尺寸摆放子视图的位置,子视图的位置是相对于父视图而言的,所以View.onLayout方法是空实现,在自定义view中继承ViewGroup的话就要实现onLayout这个方法。
在LinearLayout中他实现了onLayout方法,所以他分成了垂直布局和水平布局。
在他的垂直布局方法中有这么一个循环,他遍历每一个子View然后取出他们的宽高,还有就是根据下面子VIew的LayoutParama的测量规格,最终利用这些测量参数会调用serChildFrame方法去绘制子View中屏幕中的位置。
四、draw
在经过了测量和摆放之后,就可以在屏幕上绘制流程。
draw中两个容易混淆的方法:
(1)、invalidate():当调用的时候就是请求安卓系统,如果视图大小没有变化就不会调动onLayout这个试图摆放方法。
(2)、requestLayout():当布局的尺寸、方向发生变化的时候我们就会手动去调用这个方法,这个方法就会触发meare、layout过程,但是不会调用draw方法。