Viewmeasure函数

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {        if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||                widthMeasureSpec != mOldWidthMeasureSpec ||                heightMeasureSpec != mOldHeightMeasureSpec) {            // first clears the measured dimension flag            mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;            resolveRtlPropertiesIfNeeded();            // measure ourselves, this should set the measured dimension flag back            onMeasure(widthMeasureSpec, heightMeasureSpec);            // flag not set, setMeasuredDimension() was not invoked, we raise            // an exception to warn the developer            if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) {                throw new IllegalStateException("onMeasure() did not set the"                        + " measured dimension by calling"                        + " setMeasuredDimension()");            }            mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;        }        mOldWidthMeasureSpec = widthMeasureSpec;        mOldHeightMeasureSpec = heightMeasureSpec;}

参数widthMeasureSpec和heightMeasureSpec由父View构建,表示父View给子View的测量要求,这个值就是根据XML里面设置的View的layout_width和layout_height来构建的(其实不只是这样的),总之,这两个参数是父布局传给子View的。

DecorView根布局的参数widthMeasureSpec和heightMeasureSpec在代码里面初始化的时候给出。

onMeasure的默认实现

// widthMeasureSpec和heightMeasureSpec 为父类传过来的宽高。    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));    }

getDefaultSize实现

public static int getDefaultSize(int size, int measureSpec) {        int result = size;        int specMode = MeasureSpec.getMode(measureSpec);        int specSize = MeasureSpec.getSize(measureSpec);        switch (specMode) {        case MeasureSpec.UNSPECIFIED:            result = size;            break;        case MeasureSpec.AT_MOST:        case MeasureSpec.EXACTLY:// wrap_content会封装成AT_MOST  具体的精确值或者match_parent会封装成EXACTLY(后面会看到)//因此可以看出默认的测量实现中设置成包裹内容(wrap_content)和精确值都会将宽高设置成MeasureSpec中封装的size值            result = specSize;            break;        }        return result;    }

ViewGroup:View的measure的参数就是父布局传过来的,而ViewGroup又是继承自View的,那么他的measure的参数其实也是父类传过来的。DecorView根布局的参数widthMeasureSpec和heightMeasureSpec在代码里面初始化的时候给出。

//某个ViewGroup类型的视图  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    //必须调用super.ononMeasure()或者直接调用setMeasuredDimension()方法设置该View大小,否则会报异常。    super.onMeasure(widthMeasureSpec , heightMeasureSpec)       //setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),       //        getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));           //遍历每个子View    for(int i = 0 ; i < getChildCount() ; i++){      View child = getChildAt(i);  //调用子View的onMeasure,默认的情况又回到了上面的实现。//这个只是示意一下大致的逻辑    child.onMeasure(childWidthMeasureSpec, childHeightMeasureSpec);    }  }

ViewGroup提供了measureChildren来进行测量

//widthMeasureSpec 和  heightMeasureSpec 表示该父View的布局要求  //遍历每个子View,然后调用measureChild()方法去实现每个子View大小  protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {      final int size = mChildrenCount;      final View[] children = mChildren;      for (int i = 0; i < size; ++i) {          final View child = children[i];          if ((child.mViewFlags & VISIBILITY_MASK) != GONE) { // 不处于 “GONE” 状态              measureChild (child, widthMeasureSpec, heightMeasureSpec);          }  
//测量每个子View高宽时,清楚了该View本身的边距大小,即android:padding属性 或android:paddingLeft等属性标记  protected void measureChild(View child, int parentWidthMeasureSpec,          int parentHeightMeasureSpec) {      final LayoutParams lp = child.getLayoutParams(); // LayoutParams属性      //设置子View的childWidthMeasureSpec属性,去除了该父View的边距值  mPaddingLeft + mPaddingRight      final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,              mPaddingLeft + mPaddingRight, lp.width);      //设置子View的childHeightMeasureSpec属性,去除了该父View的边距值  mPaddingTop + mPaddingBottom      final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,              mPaddingTop + mPaddingBottom, lp.height);    //可以很清楚的看到传递给子View的两个参数是由父类确定的,由getChildMeasureSpec得到的。    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);  }

还有和measureChild类似的函数,比如measureChildWithMargins

protected void measureChildWithMargins(View child,            int parentWidthMeasureSpec, int widthUsed,            int parentHeightMeasureSpec, int heightUsed) {        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin                        + widthUsed, lp.width);        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin                        + heightUsed, lp.height);        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);    }
getChildMeasureSpec// spec参数表示该父View本身所占的widthMeasureSpec 或  heightMeasureSpec值  // padding参数表示该父View的边距大小,见于android:padding属性 或android:paddingLeft等属性标记  // childDimension参数表示该子View内部LayoutParams属性的值,可以是wrap_content、match_parent、一个精确指(an exactly size),   public static int getChildMeasureSpec(int spec, int padding, int childDimension) {      int specMode = MeasureSpec.getMode(spec);  //获得父View的mode      int specSize = MeasureSpec.getSize(spec);  //获得父View的实际值        int size = Math.max(0, specSize - padding); //父View为子View设定的大小,减去边距值,        int resultSize = 0;     int resultMode = 0;       switch (specMode) {      // Parent has imposed an exact size on us      //1、父View是EXACTLY的 !      case MeasureSpec.EXACTLY:           //1.1、子View的width或height是个精确值 (an exactly size)          if (childDimension >= 0) {                        resultSize = childDimension;         //size为精确值              resultMode = MeasureSpec.EXACTLY;    //mode为 EXACTLY 。          }           //1.2、子View的width或height为 MATCH_PARENT/FILL_PARENT           else if (childDimension == LayoutParams.MATCH_PARENT) {              // Child wants to be our size. So be it.              resultSize = size;                   //size为父视图大小              resultMode = MeasureSpec.EXACTLY;    //mode为 EXACTLY 。          }           //1.3、子View的width或height为 WRAP_CONTENT          else if (childDimension == LayoutParams.WRAP_CONTENT) {              // Child wants to determine its own size. It can't be              // bigger than us.              resultSize = size;                   //size为父视图大小              resultMode = MeasureSpec.AT_MOST;    //mode为AT_MOST 。          }          break;        // Parent has imposed a maximum size on us      //2、父View是AT_MOST的 !          case MeasureSpec.AT_MOST:          //2.1、子View的width或height是个精确值 (an exactly size)          if (childDimension >= 0) {              // Child wants a specific size... so be it              resultSize = childDimension;        //size为精确值              resultMode = MeasureSpec.EXACTLY;   //mode为 EXACTLY 。          }          //2.2、子View的width或height为 MATCH_PARENT/FILL_PARENT          else if (childDimension == LayoutParams.MATCH_PARENT) {              // Child wants to be our size, but our size is not fixed.              // Constrain child to not be bigger than us.              resultSize = size;                  //size为父视图大小              resultMode = MeasureSpec.AT_MOST;   //mode为AT_MOST          }          //2.3、子View的width或height为 WRAP_CONTENT          else if (childDimension == LayoutParams.WRAP_CONTENT) {              // Child wants to determine its own size. It can't be              // bigger than us.              resultSize = size;                  //size为父视图大小              resultMode = MeasureSpec.AT_MOST;   //mode为AT_MOST          }          break;        // Parent asked to see how big we want to be      //3、父View是UNSPECIFIED的 !      case MeasureSpec.UNSPECIFIED:          //3.1、子View的width或height是个精确值 (an exactly size)          if (childDimension >= 0) {              // Child wants a specific size... let him have it              resultSize = childDimension;        //size为精确值              resultMode = MeasureSpec.EXACTLY;   //mode为 EXACTLY          }          //3.2、子View的width或height为 MATCH_PARENT/FILL_PARENT          else if (childDimension == LayoutParams.MATCH_PARENT) {              // Child wants to be our size... find out how big it should              // be              resultSize = 0;                        //size为0! ,其值未定              resultMode = MeasureSpec.UNSPECIFIED;  //mode为 UNSPECIFIED          }           //3.3、子View的width或height为 WRAP_CONTENT          else if (childDimension == LayoutParams.WRAP_CONTENT) {              // Child wants to determine its own size.... find out how              // big it should be              resultSize = 0;                        //size为0! ,其值未定              resultMode = MeasureSpec.UNSPECIFIED;  //mode为 UNSPECIFIED          }          break;      }      //根据上面逻辑条件获取的mode和size构建MeasureSpec对象。      return MeasureSpec.makeMeasureSpec(resultSize, resultMode);  } 

getChildMeasureSpec(int spec, int padding, int childDimension)函数表示传递给子ViewonMeasure函数中的参数是由父布局和子布局共同决定的。

Spec参数表示父View本身的widthMeasureSpecheightMeasureSpec值,

childDimension参数表示该子View内部LayoutParams属性的值,可以是wrap_contentmatch_parent、一个精确值(an exactly size)

最外层的ViewonMeasure函数中的第一个参数是在代码中初始化时给出的

childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);  childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);

private int getRootMeasureSpec(int windowSize, int rootDimension) {      int measureSpec;      switch (rootDimension) {      case ViewGroup.LayoutParams.MATCH_PARENT:          measureSpec = 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;  }  

使用了MeasureSpec.makeMeasureSpec()方法来组装一个MeasureSpec,当rootDimension参数等于MATCH_PARENT的时候,MeasureSpec的specMode就等于EXACTLY,当rootDimension等于WRAP_CONTENT的时候,MeasureSpec的specMode就等于AT_MOST。并且MATCH_PARENT和WRAP_CONTENT时的specSize都是等于windowSize的,也就意味着根视图总是会充满全屏的。


lp.width是MATCH_PARENT,因此测量得到的measureSpec为屏幕大小的EXACTLY,也就是说,最顶层的View的onMeasure函数里面的参数为屏幕尺寸是EXACTLY的。


经过上面的分析可以看出果然是:传递给ViewonMeasurewidthMeasureSpecheightMeasureSpec值是经过父布局计算的。

getChildMeasureSpec函数的实际意义如下图所示:

Android之View的视图测量过程_第1张图片


参考文章:

http://blog.csdn.net/fengye810130/article/details/9181531
http://blog.csdn.net/guolin_blog/article/details/16330267



更多相关文章

  1. android camera根据屏幕图像大小设置显示
  2. android在java中动态改变控件大小
  3. Android 数据存储(数据库、文件、参数)操作实例
  4. Android动态设置View的位置和大小
  5. android 横竖屏切换 分辨率大小设置的模拟器
  6. Android得到SD卡文件夹大小以及删除文件夹操作
  7. Android 系统(84)---查看分区的大小
  8. OpenGL ES教程I之创建OpenGL视图(原文对照)
  9. android自定义progressbar图片大小自适应

随机推荐

  1. android Application的生命周期
  2. Android TextView中插入图片
  3. 【转】 关于Android堆内存的设置
  4. Android 判断 app 是否安装的方法 (nativ
  5. Android中OptionMenu的使用
  6. 可以下载Android 源代码的repo源文件
  7. Android初级教程XUtils实现“断点续传”
  8. Android学习——在线查看android源代码的
  9. android 以httpclient方式把数据提交到服
  10. Android 中常见bug 总结