ViewRootImpl.performTraversals流程:
measure、layout、draw流程:
Measure:
①单一View:measure() -> onMeasure() -> getDefaultSize() 计算View的宽/高值 -> setMeasuredDimension存储测量后的View宽/高
②ViewGroup:
-> measure()
-> 需要重写onMeasure,ViewGroup没有定义测量的具体过程,是一个抽象类,其测量过程的onMeasure方法需要各个子类去实现,遍历测量ViewGroup中所有的View。如:LinearLayout、RelativeLayout、FrameLayout等等,这些控件的特性都是不一样的,测量规则自然也都不一样。
-> 根据父容器的MeasureSpec和子View的LayoutParams等信息计算子View的MeasureSpec
-> 合并所有子View计算出ViewGroup的尺寸
-> setMeasuredDimension 存储测量后的宽 / 高。
Layout:
根据上一步measure子View所得到的布局大小和布局参数,从顶层父View向子View递归调用view.layout方法确定各元素的位置,子元素如果是 ViewGroup 的子类,再次执行 onLayout,如此循环往复,直到所有子元素的位置都被确定,整个 View 树的 layout 过程就执行完了。
Draw:
绘制视图。ViewRoot创建一个Canvas对象,然后调用OnDraw()。
六个步骤:
①绘制视图背景;
②保存画布图层(Layer);
③绘制View内容;
④绘制View的子视图,如果没有就不用;
⑤还原图层(Layer);
⑥绘制View装饰(例如滚动条等等)。
MeasureSpec是什么?
MeasureSpec是一个32位的整形值,它的高2位表示测量模式SpecMode,低30位表示规格大小SpecSize。MeasureSpec是View类的一个静态内部类,用来说明应该如何测量这个View。它有三种测量模式:
EXACTLY:精确测量,视图宽高指定为match_parent或具体数值时生效,表示父视图已经决定了子视图的精确大小,这种模式下View的测量值就是SpecSize的值。
AT_MOST:最大值,当视图的宽高指定为wrap_content时生效,此时子视图的尺寸可以是不超过父视图允许的最大尺寸的任何尺寸。
UNSPECIFIED:不指定,父视图没有限制子视图的大小,子视图可以是想要的任何尺寸,通常用于系统内部,应用开发中很少用到。
MeasureSpec通过将SpecMode和SpecSize打包成一个int值来避免过多的对象内存分配,为了方便操作,其提供了打包和解包的方法,打包方法为makeMeasureSpec,解包方法为getMode和getSize。
子View创建MeasureSpec的规则是什么?
根据父容器的MeasureSpec和子View的LayoutParams等信息计算子View的MeasureSpec