View的工作原理
文章目录
1)View工作流程
2)measure过程
3)layout过程
4)draw过程
5)自定义View
View工作流程
- View的绘制流程是从
ViewRoot
和performTraversals
开始。- ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带。
- performTraversals()依次调用
performMeasure()
、performLayout()和performDraw()三个方法,分别完成顶级 View的绘制。其中,performMeasure()会调用measure()
,measure()中又调用onMeasure()
,实现对其所有子元素的measure过程,这样就完成了一次measure过程;接着子元素会重复父容器的measure过程,如此反复至完成整个View树的遍历。layout和draw同理。 measure
测量->layout
布局->draw
绘制
measure过程
- 确定View的测量宽高,对应
onMeasure()
方法。 - MeasureSpec
- 通过宽测量值widthMeasureSpec和高测量值heightMeasureSpec决定View的大小
- 一个32位int值,高2位代表SpecMode,低30位代表SpecSize。值由子View的布局参数LayoutParams和父容器的MeasureSpec值共同决定。
- 三种模式
- UNSPECIFIED:父容器不对View有任何限制,要多大有多大。常用于系统内部。
- EXACTLY:对应LyaoutParams中的match_parent或具体数值。
- AT_MOST:View的大小不能大于SpecSize这个值。对应LayoutParams中的wrap_content。
- View的measure
- 只有一个原始的View,通过measure()即可完成测量
- ViewGroup的measure
- 除了完成ViewGroup自身的测量外,还会遍历去调用所有子元素的measure方法。
- 使用measureChildren()
layout过程
- 确定View的最终宽高和四个顶点的位置,对应
onLayout()
方法。 - 单一View的layout过程
- 调用layout(),接着调用onLayout()
- ViewGroup的layout过程
- 从顶级View开始依次调用layout(),其中子View的layout()会调用setFrame()来设定自己的四个顶点(mLeft、mRight、mTop、mBottom),接着调用onLayout()来确定其坐标
draw过程
- 将View 绘制到屏幕上,对应
onDraw()
三个方法。 - 单一View的draw过程
- 绘制顺序:
- 1.绘制背景:
background.draw(canvas)
- 2.绘制自己:
onDraw(canvas)
- 3.绘制children:
dispatchDraw(canvas)
- 4.绘制装饰:
onDrawScrollBars(canvas)
- 1.绘制背景:
- ViewGroup的draw过程
- ViewGroup绘制自身
- ViewGroup遍历子View,然后绘制其所有子View
- 自上而下、一层层地传递下去,直到完成整个View树的draw过程
自定义View
- 继承View重写onDraw方法
- 实现一些不规则的效果,重写onDraw方法,需要自己支持wrap_content,并且padding也需要自己处理
- 继承ViewGroup派生特殊的Layout
- 实现自定义的布局
- 继承特定的View
- 扩展某种已有的View功能,不需要自己实现wrap_content和padding
- 继承特定的ViewGroup
- 不需要自己处理ViewGroup的测量和布局这两个过程。
- 注意事项
- 让View支持wrap_content
- 让View支持padding
- 不要在View中使用Handler
- View中如果有线程或者动画,参考onDetachedFromWindow
- 处理好滑动冲突
参考
《Android开发艺术与探索》
开发艺术之View
自定义View基础
自定义View Draw过程