回顾:1.按顺序发送INPUT,ANIMATION,TRASVEL并处理他们各自的doFrame方法 先处理输入事件在处理动画,最后的TRASVEL会进行调用到ViewRootImpl中的doTrasvel回调,这个回调里面会进行measure,layout和draw。
在起始的测量measure阶段我们需要获取到View的真实宽高,这个需要借助于父View的测量模式和当前View的宽高一起来决定最终View的宽高;ViewGroup也是一样的需要去循环获取子View的宽高最后决定自己的宽高,测量模式和宽高会被封装到一个叫MeasureSpec的类中。
MeasureSpec是View的内部类,其封装了一个View的规格尺寸,包括View的宽和高的信息,他的作用是在Measure流程中,系统会将View的LayoutParams根据父容器所施加的规则转换成对应的MeasureSpe,然后在onMeasure中根据这个MeasureSpec来确定View的宽和高
MeasureSpec代表了32位的int值,高两位代表SpecMode,低30位表示SpecSize。
MeasureSpec的模式SpecMode
UNSPECIFIED:未定义模式,父容器不做限制
AT_MOST:最大模式,对应于wrap_content,子View的大小是父View的SpecSize
EXACTLY:精确模式,对应match_content和具体给出的宽高数值
每一个View都有一个MeasureSpec,在测量过程中可以通过makeMeasureSpec保存View的宽高,getMode和getSize的到宽高和测量模式。
DecoreView的MeasureSpec
在前面一篇文章中说到顶层的View其实是DecoreView,他也属于一个View,那么他的MeasureSpec又是怎样的呢?
在ViewRootImpl中调用的performTraveals方法(参照开头给出的文章链接)中,会获取根View代表宽的MeasureSpec还有高的MeasureSpec:
可以看到DecoreView的宽高其实就是Window的宽高,而rootDimension是DecoreView自身的LayoutParams,由此可见:DecoreView的宽高是按照Window的宽高和本身的LayoutParams决定
接着将DecoreView获取到的MeasureSpec传递到齐子View中,进行不断的遍历和重复该过程,直到Measure完成后进入到layout中。