http://www.jianshu.com/p/75dc9e4b67ae
基本知识
1、首先明确的是,ViewRoot(ViewRootImpl)是连接WindowManager和DecorView(内容部分区域id叫R.id.content)的纽带,但是实际上最终还是通过WindowSession(Binder)调用WindowManagerService处理。
这里主要比较重要的一个问题是,View的绘制流程(测量、布局、绘制)是由ViewRootImpl控制:
2、MeasureSpec,一个32位int值,高2位代表SpecMode(测量模式),低30位代表SpecSize( 某种测量模式下的规格大小)。SpecMode有三类:UNSPECIFIED(系统内部)、EXACTLY精确模式(父容器已经检测出精确代销,View的最总大小就是SpecSize值,对应LyaoutParams中的match_parent或具体数值)、AT_MOST最大模式(父容器指定了一个可用大小即SpecSize,View的大小不能大于这个值,具体是什么值要看不同View的具体实现,对应LayoutParams中的wrap_content)。
MeasureSpec由LayoutParams和父容器共同决定,其值是父元素对子元素的约束。
View工作流程
1、View工作流程主要是指measure(确定View的测量宽高)、layout(确定View的最总宽高和四个顶点的位置)、draw(将View绘制到屏幕上)这三大流程。
2、由于measure()方法为final,不能被重写,所以主要看onMeasure()即可,其他类似。
3、直接继承View的自定义控件,需要重写onMeasure方法并且设置wrap_content时的自身大小,否则在布局中使用了wrap_content相当于使用match_parent。解决方法:在onMeasure时,给View指定一个内部宽/高,并在wrap_content时设置即可,其他情况沿用系统的测量值即可。
4、对于ViewGroup来说,除了完成自己的measure过程之外,还会遍历去调用所有子元素的measure方法,个个子元素再递归去执行这个过程,和View不同的是,ViewGroup是一个抽象类,没有重写View的onMeasure方法,提供了measureChildren方法。
5、measure完成之后,通getMeasureWidth/Height方法就可以获取View的测量宽/高,需要注意的是,在某些极端情况下,系统可能要多次measure才能确定最终的测量宽/高,比较好的习惯是在onLayout方法中去获取测量宽/高或者最终宽/高。
6、由于View的measure过程和Activity的生命周期不同步,所以如果View还没有测量完毕获取的宽高是0,四种解决办法:①onWindowFocusChanged:表示View已经初始化完毕,但是会被调用多次。②view。post(runnable):相当于把runnable投递消息队列尾部。③ViewTreeObserver:使用ViewTreeObserver众多回调接口可以完成此功能,比如onGlobalLayoutListener这个接口,伴随View树的状态改变等,会被多次调用。④view.measure:match_parent无法测出,因为无法得知父容器剩余空间。具体可参考书籍。
7、在View的默认实现中,View的测量宽/高和最终宽/高是相等的,测量宽/高形成于View的measure过程,而最终宽/高形成于View的layout过程。有些情况会存在measure和layout不一致。
8、draw过程即为绘制。顺序是:绘制背景background(canvas)--绘制自己(onDraw)--绘制children(dispatchDraw)--绘制装饰(onDrawScrollBars)