今天我们来复习下View的绘制流程。View是Android中所有控件的基类,是控件的一种抽象,代表了一个控件。
Android进阶——Android视图工作机制之measure、layout、draw
measure –> layout –> draw 测量 –> 布局 –>绘制 measure :测量出View的宽/高; layout:确定View最终宽/高四个顶点的位置; draw:将View绘制在屏幕上;
指定视图宽度、高度的参数有 match_parent、wrap_content、固定值(100dp)三种。
测量规则,代表一个32位的int值,将SpecMode、SpecSize包装成一个int值来避免过多的对象内存分配;高2位代表SpecMode(测量模式), 低30位代表SpecSize(在某种测量模式下测量出的具体值)。
UNSPECIFIED: 父容器不对View有任何限制,要多大给多大,一般用于系统内部,表示一种测量状态。
EXACTLY: 父容器检测出View所需要的精确大小,这时候View的值就是SpecSize;它对应于LayoutParams中的 match_parent 和 具体的数值两种模式。
AT_MOST: 父容器指定了一个可用大小即SpecSize,View的大小不能大于这个值;它对应于LayoutParams中的 wrap_content 模式。
子View的MeasureSpec由父容器的MeasureSpec和自身的LayoutParams来共同决定的。
public void layout(int l, int t, int r, int b){} 确定View本身的位置。
protected void onLayout(boolean changed, int left, int top, int right, int bottom) { } 确定所有子元素的位置; 父容器的位置确定后,它在onLayout中会遍历所有的子元素并调用其layout方法,在layout方法中会调用onLayout方法。
1、绘制背景:drawBackground(canvas); 2、绘制自己 : onDraw(canvas); 3、绘制childen :dispatchDraw(canvas); 4、绘制装饰: onDrawForeground(canvas);
invalidate()和requestLayout(),常用于View重绘和更新,其主要区别如下:
invalidate方法只会执行onDraw方法;
requestLayout方法只会执行onMeasure方法和onLayout方法,并不会执行onDraw方法;
所以当我们进行View更新时,若仅View的显示内容发生改变且新显示内容不影响View的大小、位置,则只需调用invalidate方法;若View宽高、位置发生改变且显示内容不变,只需调用requestLayout方法;若两者均发生改变,则需调用两者,按照View的绘制流程,推荐先调用requestLayout方法再调用invalidate方法。
invalidate方法用于UI线程中重新绘制视图 postInvalidate方法用于非UI线程中重新绘制视图,省去使用handler