一、ViewRoot和DecorView
ViewRoot对应的是ViewRootImpl类,它是连接WindowManager和DecorView的桥梁,View的measure,layout,draw都是由ViewRoot完成的。在Activity的线程中,当Activity对象创建后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,并将ViewRootimpl对象和DecorView建立联系。源码如下:
View的绘制是从ViewRoot的performTraversals开始的,它经过measure,layout,draw三个步骤将view显示出来,measure负责测量View的宽高,layout负责测量View的位置,draw负责将View绘制显示出来。performTraversals的大致流程:
performTraversals依次调用performMeasure,performLayout,performDraw方法,三个方法完成顶级View的绘制,performMeasure方法调用measure,measure又调用onMeasure方法,onMeasure方法中则会对所有的子元素进行measure过程,这个时候measure流程就从父容器中传到子元素中了,如此反复就完成View树的绘制了。其余两个流程与之类似。
DecorView作为顶级View,它包含一个竖直方向的LinearLayout,在这个LinearLayout中含有上下两个部分,上面为标题栏,下面为内容栏。在Activity的setContentView方法中就是将布局加载到内容栏中。内容栏是id为content的FrameLayout。
二、MeasureSpec
MeasureSpec是View的内部类代表一个int值,高两位表示SpecMode,低三十位表示SpecSize。
MeasureSpec将SpecMode和SpecSize包装成一个int值,防止过多的内存分配,其含有打包和解包的方法。
SpecMode有如下三类:
- EXACTLY:父容器已检测出View所需精确的大小,这个时候View的最终大小就是SpecSize指定的大小,对应的是LayoutParams的match_parent和指定具体大小值两种模式
- AT_MOST:父容器指定一个可用的大小SpecSize,View的大小不能大于这个值,具体是什么看不同View的实现。它对应于LayoutParams中的wrap_content
-
UNSPECIFIED:父容器不对View有任何限制,要多大给多大,这种情况一般用于系统内部
普通的View由父容器的MeasureSpec和自身的LayoutParams决定
三、View测量绘制流程
1.measure过程
View的measure过程
View的measure方法是final的不可以被重写,所以直接看onMeasure的实现。
我们看一下getDefaultSize方法实现
这个方法会根据不同的mode返回不同的size
再看一下getSuggestedMinimumWidth方法
此方法会查看背景是否为空,若为空则返回mMinHeight否则返回mMinHeight和背景高度的最大值。(mMinHeight对应属性minHeight)
继承View需要自己设置当wrap_content模式下的宽高
ViewGroup的measure过程
对于ViewGroup,除了完成自己的measure过程,还需要遍历完成子元素的measure过程,由于ViewGroup是抽象类,因此它没有重写onMeasure方法,但是它提供了一个measureChildren的方法。
measureChildren方法遍历子元素,然后调用measureChild方法
measureChild就是抽取子元素的LayoutParams和自己的MeasureSpec构成子元素的MeasureSpec
因为ViewGroup的onMeasure需要子类去实现,因为不同的Layout有不同的布局特性。
借用一下厘米姑娘的图
借用一下厘米姑娘的图
2. layout过程
首先顶级View会调用layout,子元素会通过setFrame确定四个顶点位置,接着调用onLayout,父容器确定子元素的位置。这个方法没有具体实现,ViewGroup有不同的布局特性。
借用一下厘米姑娘的图
3.draw过程
(1)绘制背景 background.draw
(2)绘制自己 onDraw
(3)绘制children dispatchDraw
(4) 绘制装饰 onDrawScrollBars
四、自定义View
1.自定义View的分类
- 继承View重写OnDraw方法
- 继承ViewGroup派生特殊的Layout
- 继承特定的View(Text View)
- 继承特定的ViewGroup(LinearLayout)
2.自定义须知
- 让Viwe支持wrap_content
- 如果有必要,让你的View支持Padding
- 尽量在View中使用Handler
- View中如果有线程或者动画需要及时停止(在onDetachedFromWindow)
- View带有滑动嵌套时需要处理好滑动冲突













网友评论