`MeasureSpec`源码

`首先我们要理解的是widthMeasureSpec, heightMeasureSpec这两个参数是从哪里来的?onMeasure()函数由包含这个View的具体的ViewGroup调用,因此值也是从这个ViewGroup中传入的。这里我直接给出答案:子类View的这两个参数,由ViewGroup中的layout_width,layout_height和padding以及View自身的layout_margin共同决定。权值weight也是尤其需要考虑的因素,有它的存在情况可能会稍微复杂点。

了解了这两个参数的来源,还要知道这两个值的作用。我们只取heightMeasureSpec作说明。这个值由高32位和低16位组成,高32位保存的值叫specMode,可以通过如代码中所示的MeasureSpec.getMode()获取;低16位为specSize,同样可以由MeasureSpec.getSize()获取。那么specMode和specSize的作用有是什么呢?要想知道这一点,我们需要知道代码中的最后一行,所有的View的onMeasure()的最后一行都会调用setMeasureDimension()函数的作用——这个函数调用中传进去的值是View最终的视图大小。也就是说onMeasure()中之前所作的所有工作都是为了最后这一句话服务的。 `


  • 关于以上内容有人说:

  • 我们只取heightMeasureSpec作说明。这个值由高32位和低16位组成,高32位保存的值叫specMode。
    int型数据到底是有多少位,难道是48位,既然理解的这么深入,这个高32位和低16位是错误的吧。但是我看到网上都是这样的感觉都是这个复制那个,那个复制这个的。

  • 我也好奇,来辨析一下


注意看源码中的中文

MeasureSpec源码

/**
  * A MeasureSpec encapsulates the layout requirements passed from parent to child.
  * Each MeasureSpec represents a requirement for either the width or the height.
  * A MeasureSpec is comprised of a size and a mode. There are three possible
  * modes:
  * <dl>
  * <dt>UNSPECIFIED</dt>
  * <dd>
  * The parent has not imposed any constraint on the child. It can be whatever size
  * it wants.
  * </dd>
  *
  * <dt>EXACTLY</dt>
  * <dd>
  * The parent has determined an exact size for the child. The child is going to be
  * given those bounds regardless of how big it wants to be.
  * </dd>
  *
  * <dt>AT_MOST</dt>
  * <dd>
  * The child can be as large as it wants up to the specified size.
  * </dd>
  * </dl>
  *
  * MeasureSpecs are implemented as ints to reduce object allocation. This class
  * is provided to pack and unpack the &lt;size, mode&gt; tuple into the int.
  */
 public static class MeasureSpec {
     //自定义的MODE_SHIFT没有什么疑问
     private static final int MODE_SHIFT = 30;
     //以下 0x3(十六进制的3) 和 <<  的含义为:
     //我的理解是十六进制和十进制在这里其实是没有任何区别的。我想不明白这个程序员为什么会这么写 -_-
     //实际的二进制是:11000000 00000000 00000000 00000000
     private static final int MODE_MASK  = 0x3 << MODE_SHIFT;

     /**
      * Measure specification mode: The parent has not imposed any constraint
      * on the child. It can be whatever size it wants.
      *///实际的二进制是:00000000 00000000 00000000 00000000
     public static final int UNSPECIFIED = 0 << MODE_SHIFT;

     /**
      * Measure specification mode: The parent has determined an exact size
      * for the child. The child is going to be given those bounds regardless
      * of how big it wants to be.
      *///实际的二进制是:01000000 00000000 00000000 00000000
     public static final int EXACTLY     = 1 << MODE_SHIFT;

     /**
      * Measure specification mode: The child can be as large as it wants up
      * to the specified size.
      *///实际的二进制是:10000000 00000000 00000000 00000000
     public static final int AT_MOST     = 2 << MODE_SHIFT;
     //也就是说int类型的第31 和 32位确定了这个模式

     /**
      * Creates a measure specification based on the supplied size and mode.
      *
      * The mode must always be one of the following:
      * <ul>
      *  <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li>
      *  <li>{@link android.view.View.MeasureSpec#EXACTLY}</li>
      *  <li>{@link android.view.View.MeasureSpec#AT_MOST}</li>
      * </ul>
      *
      * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's
      * implementation was such that the order of arguments did not matter
      * and overflow in either value could impact the resulting MeasureSpec.
      * {@link android.widget.RelativeLayout} was affected by this bug.
      * Apps targeting API levels greater than 17 will get the fixed, more strict
      * behavior.</p>
      *
      * @param size the size of the measure specification
      * @param mode the mode of the measure specification
      * @return the measure specification based on size and mode
      */
     public static int makeMeasureSpec(int size, int mode) {
         if (sUseBrokenMakeMeasureSpec) {
             return size + mode;
         } else {
           //通过上面对Mode的解释这一句代码也就不难理解了实际上就是拼接呢。
           //size只取31和32位的内容和mode中1-30位的内容拼接起来
             return (size & ~MODE_MASK) | (mode & MODE_MASK);
         }
     }

     /**
      * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED
      * will automatically get a size of 0. Older apps expect this.
      *
      * @hide internal use only for compatibility with system widgets and older apps
      */
     public static int makeSafeMeasureSpec(int size, int mode) {
         if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) {
             return 0;
         }
         return makeMeasureSpec(size, mode);
     }

     /**
      * Extracts the mode from the supplied measure specification.
      *
      * @param measureSpec the measure specification to extract the mode from
      * @return {@link android.view.View.MeasureSpec#UNSPECIFIED},
      *         {@link android.view.View.MeasureSpec#AT_MOST} or
      *         {@link android.view.View.MeasureSpec#EXACTLY}
      */
     public static int getMode(int measureSpec) {
         return (measureSpec & MODE_MASK);
     }

     /**
      * Extracts the size from the supplied measure specification.
      *
      * @param measureSpec the measure specification to extract the size from
      * @return the size in pixels defined in the supplied measure specification
      */
     public static int getSize(int measureSpec) {
         return (measureSpec & ~MODE_MASK);
     }

     static int adjust(int measureSpec, int delta) {
         final int mode = getMode(measureSpec);
         int size = getSize(measureSpec);
         if (mode == UNSPECIFIED) {
             // No need to adjust size for UNSPECIFIED mode.
             return makeMeasureSpec(size, UNSPECIFIED);
         }
         size += delta;
         if (size < 0) {
             Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size +
                     ") spec: " + toString(measureSpec) + " delta: " + delta);
             size = 0;
         }
         return makeMeasureSpec(size, mode);
     }

     /**
      * Returns a String representation of the specified measure
      * specification.
      *
      * @param measureSpec the measure specification to convert to a String
      * @return a String with the following format: "MeasureSpec: MODE SIZE"
      */
     public static String toString(int measureSpec) {
         int mode = getMode(measureSpec);
         int size = getSize(measureSpec);

         StringBuilder sb = new StringBuilder("MeasureSpec: ");

         if (mode == UNSPECIFIED)
             sb.append("UNSPECIFIED ");
         else if (mode == EXACTLY)
             sb.append("EXACTLY ");
         else if (mode == AT_MOST)
             sb.append("AT_MOST ");
         else
             sb.append(mode).append(" ");

         sb.append(size);
         return sb.toString();
     }
 }
综上,
  • 并不是前32位来确定模式而是一个int类型的31和31位两位来确定模式–
    也就是说getMode(data);得到的是data的31和32位为有效位1-30位为零的int结果
  • getSize(data);得到的是data的1-30位为有效位31和32位为零的int结果。
  • 本文对一个int类型变量的二进制从右到左依次称为第1——32位。
  • 相关:JAVA位移运算符了解<< >> >>>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值