先来张View体系中measure()流程的时序图
注意:1.以下MeasureSpec用ms来代替(ms具体会在后面介绍)
2.该时序图描述的是从ViewRootImpl开始的measure()过程,因为ViewRootImpl是window与view连接的枢纽
3.该时序图着重于大概流程及重要方法的作用,具体代码细节会放到后面介绍
4.DecorView作为顶级View,本身是一个frameLayout,所以也是一个ViewGroup
MesureSpec简介 (以下简称ms)
在view的测量过程中,ms起着非常重要的作用,ms在某种程度上来说更像是一种测量的标准。
ms是一个32位的int值,前2位代表测量模式,后30位代表测量大小
测量模式(Specmode)一共分为3种:
UNSPECIFIED: 父容器不对子view限制,这种情况一般我们用不到,系统内部使用
EXACTLY : 父容器可以算出View的具体的大小,一般对应于 具体值或者match_parent
AT_MOST : 父容器指定一个值,子view不能超过这个值,一般对应于 wrap_content
View关于MesureSpec的计算
一般情况下,一个view的ms的测量是根据父容器的ms和本身的LayoutParams来决定的,根据一些规则,在父容器中算出ms,然后父容器调用此view的measure()方法将结果传给该view,该view接着会回掉onMeasure()将结果传给该view的实现类。 但是DecorView作为顶级View是没有父容器的,所以DecorView的ms是根据窗口的大小和自身的LayoutParams来决定的。
1.DecorView的ms计算过程:
--
/**
* desireWindowWidth : 代表屏幕的宽带 ,同理,dwh 代表屏幕的高度
**/
private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
*************************省略
//计算出DecorView的ms
** childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height); **
*************************省略
}
/**
* 计算出decorView的ms*
**/
private static int getRootMeasureSpec(int windowSize, int rootDimension) {
int measureSpec;
switch (rootDimension) {
case ViewGroup.LayoutParams.MATCH_PARENT:
//如果设置的是math_parent,屏幕长度就是view长度,模式为EXACTLY
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
break;
case ViewGroup.LayoutParams.WRAP_CONTENT:
//如果设置的是wrap_conentt,屏幕长度就是view长度,模式为AT_MOST
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
break;
default:
// 如果设置的是具体的数值,这个值就是View的长度,模式威EXANTLY
measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
break;
}
return measureSpec;