自定义View系统总结之MeasureSpec

在测量过程中,系统会将View的LayoutParams根据父容器所施加的规则转换成对应的MeasureSpec,然后再根据这个mesureSpec来测量出View的宽/高。

MeasureSpec代表一个32位int值,高2位代表SpecMode(测量模式),低30位代表SepcSize(指在某种测量模式下的规格大小)。

SpecMode有三类:

UNSPECIFIED:父容器不对VIew有任何限制,要多大给多大,这种情况一般用于系统内部,表示一种测量的状态。

EXACTLY:父容器已经检测出View所需要的精确大小,这个时候View的最终大小就是SpecSize所指定的值。它对应于LayoutParams中的match_parent和具体的数值这两种模式。

AT_MOST:父容器指定了一个可用大小即SpecSize,View的大小不能大于这个值,具体是什么值要看不同View的具体实现。它对应于LayoutParams中的wrap_content。

MeasureSpec和LayoutParamsa

系统内部是通过MeasureSpec来进行View的测量,正常情况下使用View指定MeasureSpec,但是可以给View设置LayoutParams。在View测量的时候,系统会将LayoutParams在父容器的约束下转换成对应的MeasureSpec,然后再根据这个MeasureSpec来确定View测量后的宽/高。顶级View(DecorView)其MeasureSpec由窗口的尺寸和其自身的LayoutParams来共同确定;普通的View其MeasureSpec由父容器的MeasureSpec和自身的LayoutParams来共同决定。

DecorView的MeasureSpec创建过程调用getRootMeasureSpec方法,desiredWindowWidth和desiredWindowHeight是屏幕尺寸:

childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);     //desireWindowWidth是屏幕的宽度
childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

getRootMeasureSpec方法的实现:

private static int getRootMeasureSpec(int windowSize, int rootDimension) {
      int measureSpec;
      switch (rootDimension){
      case ViewGroup.LayoutParams.MATCH_PARENT:
            mesureSpec = MeasureSpec.makeMeasureSpec(windowSize,MeasureSpec.EXACTLY);
            break;
      case ViewGroup.LayoutParams.WRAP_CONTENT:
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize,MeasureSpec.AT_MOST);
            break;
      default:
            measureSpec = MeasureSpec.makeMeasureSpec(rootDimension,MeasureSpec.EXACTLY);
            break;
      }
      return measureSpec;
}

根据它的LayoutParmas的宽/高参数来划分:

LayoutParams.MATCH_PARENT:精确模式,大小就是窗口大小;

LayoutParams.WRAP_CONTENT:最大模式,大小不定,但是不能超过窗口的大小;

固定大小:精确模式,大小为LayoutParams中指定的大小。

对于布局中的普通View来说,View的measure过程由ViewGroup传递而来。ViewGroup measureChildWithMargins方法会对子元素进行measure,在调用子元素的measure方法之前会先通过getChildMeasureSpec方法来得到子元素的MeasureSpec。getChildMeasureSpec方法的主要作用是根据父容器的MeasureSpec同时结合View本身的LayoutParams来确定子元素的MeasureSpec。

猜你喜欢

转载自www.cnblogs.com/kyun/p/10124198.html