文章按原著的顺序,先介绍所需要的基本概念,然后了解view的三大流程:measure(尺寸)、layout在(位置)、draw(画出来)
- 基本概念:
- 了解ViewRoot和DecorView
- 理解MeasureSpec
- View的工作流程
- 自定义View(略)
了解ViewRoot和DecorView
(个人理解:DecorView是所有view的老大,绘制view先从老大开始;然后ViewRoot是DecorView管理者)
- ViewRoot
- ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带。
- View的绘制流程通过ViewRoot完成。
- view的绘制是通过ViewRoot的performTraversals方法开始的:performTraversals()依次调用performMeasure()、performLayout()和performDraw()三个方法,分别完成顶级View的绘制。(方法调用过程:performMeasure()==>measure()==>onMeasure(),onMeasure实现对其所有子元素的measure过程,这样就完成了一次measure过程;接着子元素会重复父容器的measure过程,如此反复至完成整个View树的遍历。layout和draw同理。)
- DecorView
- decorView就是viewRoot所提到的顶级View,一般情况下它包含一个LinearLayout,包含一个标题栏titlebar和内容栏content(Activity中setContentView就是这个content)
- content是一个FrameView,获取方式:ViewGroup content=findViewById(R.android.content)
- DecorView其实是一个FrameView,view层的事件先经过DecorView,然后再传递给我们的view
理解MeasureSpec
MeasureSpec全称是MeasureSpecification,单词意思是测量规则/测量说明书,通过宽测量值widthMeasureSpec和高测量值heightMeasureSpec决定View的大小。
MeasureSpec是一个32位int值,高2位代表SpecMode(测量模式),低30位代表SpecSize( 某种测量模式下的规格大小)。
- SpecMode三种模式
- UNSPECIFIED:父容器不对View有任何限制,要多大有多大。常用于系统内部。
- EXACTLY(精确模式):父视图为子视图指定一个确切的尺寸SpecSize。对应LyaoutParams中的match_parent或具体数值。
- AT_MOST(最大模式):父容器为子视图指定一个最大尺寸SpecSize,View的大小不能大于这个值。对应LayoutParams中的wrap_content。
对于顶级view(也就是DecorView)来说,MeasureSpec由窗口的尺寸和自身的LayoutParams共同确定;对于普通的view,MeasureSpec由父容器的MeasureSpec和自身的LayoutParams共同确定;
view的工作流程
工作流程:measure(测量尺寸)==>layout(位置)==>draw绘制
- onMeasure()方法:确定View的测量宽高
- onLayout()方法:确定View的最终宽高和四个顶点的位置
- onDraw()方法:将View 绘制到屏幕上
measure过程
view的measure过程:通过measure方法就能完成测量
ViewGroup的measure:除了完成ViewGroup自身的测量外,还会遍历去调用所有子元素的measure方法。(ViewGroup中没有重写onMeasure(),而是提供measureChildren()。)
layout过程
layout 作用是ViewGroup来确定子元素四个顶点的位置,当ViewGroup位置确定后,会在onLayout中遍历所有的子元素,并调用layout方法,layout方法中onLayout方法又会被调用。
推荐阅读:【自定义View Draw过程】
draw过程
- 绘制背景:background.draw(canvas)
- 绘制自己:onDraw(canvas)
- 绘制children:dispatchDraw(canvas) (dispatchDraw遍历所有的子元素的draw方法,进而实现子元素的draw过程)
- 绘制装饰:onDrawScrollBars(canvas)
推荐阅读:【对View工作流程的理解(源码)】
自定义view
四类不同层次的自定义view
- 继承View重写onDraw方法(主要实现一些不规则的效果。重写onDraw方法需要自己支持wrap_content,并且padding也需要自己处理)
- 继承ViewGroup派生的特殊的Layout(用于实现自定义的布局,需要合适地处理ViewGrou的测量、布局这个过程,并实现处理子元素的测量和布局过程)
- 继承特定的View(常见,一般用于扩展某种已有的View功能。不需要自己支持wrap_content和padding等)
- 继承特定的ViewGroup(如LinearLayout)
自定义View须知
- 让View支持wrap_content(如果不在onMeasure中处理,当外界再不聚中使用wrap_content时就无法达到预期的效果)
- 如有必要,让View支持padding(如果直接继承View,不在draw中处理padding,那么padding属性是无法起作用的,等等)
- 尽量不要在View中使用Handler(没必要,因为view内部本身提供了post系列的方法,完全可以代替Handler的作用)
- View中如果有线程或者动画,需要及时停止(view变得不可见时,需要及时停止线程和动画,不及时处理的话可能造成内存泄漏)
- View带有滑动嵌套时,需要处理好滑动冲突(否则会严重影响view的效果)
.(略,待功力深厚再来与之一战!)