View工作流程、自定义View

http://www.jianshu.com/p/75dc9e4b67ae

基本知识

1、首先明确的是,ViewRoot(ViewRootImpl)是连接WindowManager和DecorView(内容部分区域id叫R.id.content)的纽带,但是实际上最终还是通过WindowSession(Binder)调用WindowManagerService处理。
这里主要比较重要的一个问题是,View的绘制流程(测量、布局、绘制)是由ViewRootImpl控制:

View工作流程、自定义View_第1张图片
绘制流程

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工作流程、自定义View_第2张图片
MeasureSpec规则

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时设置即可,其他情况沿用系统的测量值即可。


View工作流程、自定义View_第3张图片
重写onMeasure

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)

自定义View

View工作流程、自定义View_第4张图片
自定义View分类
View工作流程、自定义View_第5张图片
自定义View须知

你可能感兴趣的:(View工作流程、自定义View)