AndroidMeasureSpec的理解和源码的解析

AndroidMeasureSpec的理解和源码的解析,第1张

概述Android MeasureSpec的理解源码解析MeasureSpec的创建规则:实例详解:packagecc.ww;

AndroID  MeasureSpec的理解和源码的解析

MeasureSpec的创建规则:

实例详解:

package cc.ww;  import androID.vIEw.VIEw; import androID.vIEw.VIEw.MeasureSpec; import androID.vIEw.VIEwGroup.LayoutParams; import androID.vIEw.VIEwGroup.marginLayoutParams; import androID.Widget.linearLayout;  /**  * @author http://blog.csdn.net/lfdfhl  *  * 文档描述:  * 关于MeasureSpec的理解  *  * (1) MeasureSpec基础知识  *   MeasureSpec通常翻译为"测量规格",它是一个32位的int数据.  *   其中高2位代表SpecMode即某种测量模式,低32位为Specsize代表在该模式下的规格大小.  *   可以通过:   *   int specMode = MeasureSpec.getMode(measureSpec) 获取specMode     int specsize = MeasureSpec.getSize(measureSpec) 获取Specsize           常用的SpecMode有三种:           MeasureSpec.EXACTLY       官方文档     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.          父容器已经检测出子VIEw所需要的精确大小.该子VIEw最终的测量大小即为Specsize.     (1) 当子VIEw的LayoutParams的宽(高)采用具体的值(如100px)时且父容器的MeasureSpec为 MeasureSpec.EXACTLY或者     MeasureSpec.AT_MOST或者MeasureSpec.UnspecIFIED时:          系统返回给该子VIEw的specMode就为 MeasureSpec.EXACTLY          系统返回给该子VIEw的specsize就为子VIEw自己指定的大小(childSize)          通俗地理解:          子VIEw的LayoutParams的宽(高)采用具体的值(如100px)时,那么说明该子VIEw的大小是非常明确的,明确到已经用具体px值          指定的地步了.那么此时不管父容器的specMode是什么,系统返回给该子VIEw的specMode总是MeasureSpec.EXACTLY,并且          系统返回给该子VIEw的specsize就为子VIEw自己指定的大小(childSize).         (2) 当子VIEw的LayoutParams的宽(高)采用match_parent时并且父容器的MeasureSpec为 MeasureSpec.EXACTLY时:          系统返回给该子VIEw的specMode就为 MeasureSpec.EXACTLY          系统返回给该子VIEw的specsize就为该父容器剩余空间的大小(parentleftSize)          通俗地理解:       子VIEw的LayoutParams的宽(高)采用match_parent时并且父容器的MeasureSpec为 MeasureSpec.EXACTLY.       这时候说明子VIEw的大小还是挺明确的:就是要和父容器一样大,更加直白地说就是父容器要怎样子VIEw就要怎样.       所以,如果父容器MeasureSpec为 MeasureSpec.EXACTLY那么:       系统返回给该子VIEw的specMode就为 MeasureSpec.EXACTLY,和父容器一样.          系统返回给该子VIEw的specsize就为该父容器剩余空间的大小(parentleftSize),就是父容器的剩余大小.          同样的道理如果此时,MeasureSpec为 MeasureSpec.AT_MOST呢?          系统返回给该子VIEw的specMode也为 MeasureSpec.AT_MOST,和父容器一样.          系统返回给该子VIEw的specsize也为该父容器剩余空间的大小(parentleftSize),就是父容器的剩余大小.           MeasureSpec.AT_MOST       官方文档     The child can be as large as it wants up to the specifIEd size.       父容器指定了一个可用大小即specsize,子VIEw的大小不能超过该值.     (1) 当子VIEw的LayoutParams的宽(高)采用match_parent时并且父容器的MeasureSpec为 MeasureSpec.AT_MOST时:          系统返回给该子VIEw的specMode就为 MeasureSpec.AT_MOST          系统返回给该子VIEw的specsize就为该父容器剩余空间的大小(parentleftSize)          这种情况已经在上面介绍 MeasureSpec.EXACTLY时已经讨论过了.    (2) 当子VIEw的LayoutParams的宽(高)采用wrap_content时并且父容器的MeasureSpec为 MeasureSpec.EXACTLY时:          系统返回给该子VIEw的specMode就为 MeasureSpec.AT_MOST          系统返回给该子VIEw的specsize就为该父容器剩余空间的大小(parentleftSize)          通俗地理解:          子VIEw的LayoutParams的宽(高)采用wrap_content时说明这个子VIEw的宽高不明确,要视content而定.          这个时候如果父容器的MeasureSpec为 MeasureSpec.EXACTLY即父容器是一个精确模式;这个时候简单地说          子VIEw是不确定的,父容器是确定的,那么          系统返回给该子VIEw的specMode也就是不确定的即为 MeasureSpec.AT_MOST          系统返回给该子VIEw的specsize就为该父容器剩余空间的大小(parentleftSize)     (3) 当子VIEw的LayoutParams的宽(高)采用wrap_content时并且父容器的MeasureSpec为 MeasureSpec.AT_MOST时:          系统返回给该子VIEw的specMode就为 MeasureSpec.AT_MOST          系统返回给该子VIEw的specsize就为该父容器剩余空间的大小(parentleftSize)          通俗地理解:          子VIEw的LayoutParams的宽(高)采用wrap_content时说明这个子VIEw的宽高不明确,要视content而定.          这个时候如果父容器的MeasureSpec为 MeasureSpec.AT_MOST这个时候简单地说          子VIEw是不确定的,父容器也是不确定的,那么          系统返回给该子VIEw的specMode也就是不确定的即为 MeasureSpec.AT_MOST          系统返回给该子VIEw的specsize就为该父容器剩余空间的大小(parentleftSize)                  MeasureSpec.UnspecIFIED       官方文档     The parent has not imposed any constraint on the child. It can be whatever size it wants.       父容器不对子VIEw的大小做限制.       一般用作AndroID系统内部,或者ListVIEw和ScrollVIEw.在此不做讨论.             关于这个三种测量规格下面的源码分析中体现得很明显,也可参考以下附图.      * (2) 在onMeasure()时子VIEw的MeasureSpec的形成过程分析  *   关于该技术点的讨论,请看下面的源码分析.  *  */ public class UnderstandMeasureSpec {      /**    * 第一步:    * 在VIEwGroup测量子VIEw时会调用到measureChilDWithmargins()方法,或者与之类似的方法.    * 请注意方法的参数:    * @param child    * 子VIEw    * @param parentWIDthMeasureSpec    * 父容器(比如linearLayout)的宽的MeasureSpec    * @param wIDthUsed    * 父容器(比如linearLayout)在水平方向已经占用的空间大小    * @param parentHeightmeasureSpec    * 父容器(比如linearLayout)的高的MeasureSpec    * @param heightUsed    * 父容器(比如linearLayout)在垂直方向已经占用的空间大小    *    * 在该方法中主要有四步 *** 作,其中很重要的是调用了getChildMeasureSpec()方法来确定    * 子VIEw的MeasureSpec.详情参见代码分析    */   protected voID measureChilDWithmargins(VIEw child,int parentWIDthMeasureSpec,int wIDthUsed,int parentHeightmeasureSpec,int heightUsed) {     //1 得到子VIEw的LayoutParams     final marginLayoutParams lp = (marginLayoutParams) child.getLayoutParams();     //2 得到子VIEw的宽的MeasureSpec     final int chilDWIDthMeasureSpec = getChildMeasureSpec     (parentWIDthMeasureSpec,mpaddingleft + mpaddingRight + lp.leftmargin + lp.rightmargin + wIDthUsed,lp.wIDth);     //3 得到子VIEw的高的MeasureSpec     final int childHeightmeasureSpec = getChildMeasureSpec     (parentHeightmeasureSpec,mpaddingtop + mpaddingBottom + lp.topmargin + lp.bottommargin + heightUsed,lp.height);     //4 测量子VIEw     child.measure(chilDWIDthMeasureSpec,childHeightmeasureSpec);   }         /**    * getChildMeasureSpec()方法确定子VIEw的MeasureSpec    * 请注意方法的参数:    * @param spec    * 父容器(比如linearLayout)的宽或高的MeasureSpec    * @param padding    * 父容器(比如linearLayout)在垂直方向或者水平方向已被占用的空间.    * 在measureChilDWithmargins()方法里调用getChildMeasureSpec()时注意第二个参数的构成:    * 比如:mpaddingleft + mpaddingRight + lp.leftmargin + lp.rightmargin    * 其中:    * mpaddingleft和mpaddingRight表示父容器左右两内侧的padding    * lp.leftmargin和lp.rightmargin表示子VIEw左右两外侧的margin    * 这四部分都不可以再利用起来布局子VIEw.所以说这些值的和表示:    * 父容器在水平方向已经被占用的空间    * 同理:    * mpaddingtop + mpaddingBottom + lp.topmargin + lp.bottommargin    * 表示:    * 父容器(比如linearLayout)在垂直方向已被占用的空间.    * @param childDimension    * 通过子VIEw的LayoutParams获取到的子VIEw的宽或高    *    *    * 经过以上分析可从getChildMeasureSpec()方法的第一个参数和第二个参数可以得出一个结论:    * 父容器(如linearLayout)的MeasureSpec和子VIEw的LayoutParams共同决定了子VIEw的MeasureSpec!!!    *    *    *    */    public static int getChildMeasureSpec(int spec,int padding,int childDimension) {       /**        * 第一步:得到父容器的specMode和specsize        */       int specMode = MeasureSpec.getMode(spec);       int specsize = MeasureSpec.getSize(spec);       /**        * 第二步:得到父容器在水平方向或垂直方向可用的最大空间值.        *    关于padding参见上面的分析        */       int size = Math.max(0,specsize - padding);        int resultSize = 0;       int resultMode = 0;               /**        * 第三步:确定子VIEw的specMode和specsize.        *    在此分为三种情况进行.        */       switch (specMode) {       /**        * 第一种情况:        * 父容器的测量模式为EXACTLY        *        * 请注意两个系统常量:        * LayoutParams.MATCH_PARENT=-1        * LayoutParams.WRAP_CONTENT=-2        * 所以在此处的代码:        * childDimension >= 0 表示子VIEw的宽或高不是MATCH_PARENT和WRAP_CONTENT        */       case MeasureSpec.EXACTLY:         /**          * 当父容器的测量模式为EXACTLY时如果:          * 子VIEw的宽或高是一个精确的值,比如100px;          * 那么:          * 子VIEw的size就是childDimension          * 子VIEw的mode也为MeasureSpec.EXACTLY          */         if (childDimension >= 0) {           resultSize = childDimension;           resultMode = MeasureSpec.EXACTLY;         /**          * 当父容器的测量模式为EXACTLY时如果:          * 子VIEw的宽或高是LayoutParams.MATCH_PARENT          * 那么:          * 子VIEw的size就是父容器在水平方向或垂直方向可用的最大空间值即size          * 子VIEw的mode也为MeasureSpec.EXACTLY          */         } else if (childDimension == LayoutParams.MATCH_PARENT) {           // Child wants to be our size. So be it.           resultSize = size;           resultMode = MeasureSpec.EXACTLY;         /**          * 当父容器的测量模式为EXACTLY时如果:          * 子VIEw的宽或高是LayoutParams.WRAP_CONTENT          * 那么:          * 子VIEw的size就是父容器在水平方向或垂直方向可用的最大空间值即size          * 子VIEw的mode为MeasureSpec.AT_MOST          */         } else if (childDimension == LayoutParams.WRAP_CONTENT) {           // Child wants to determine its own size. It can't be bigger than us.           resultSize = size;           resultMode = MeasureSpec.AT_MOST;         }         break;        /**        * 第二种情况:        * 父容器的测量模式为AT_MOST        *        * 请注意两个系统常量:pp        * LayoutParams.MATCH_PARENT=-1        * LayoutParams.WRAP_CONTENT=-2        * 所以在此处的代码:        * childDimension >= 0 表示子VIEw的宽或高不是MATCH_PARENT和WRAP_CONTENT        */       case MeasureSpec.AT_MOST:         /**          * 当父容器的测量模式为AT_MOST时如果:          * 子VIEw的宽或高是一个精确的值,比如100px;          * 那么:          * 子VIEw的size就是childDimension          * 子VIEw的mode也为MeasureSpec.EXACTLY          */         if (childDimension >= 0) {           // Child wants a specific size... so be it           resultSize = childDimension;           resultMode = MeasureSpec.EXACTLY;         /**          * 当父容器的测量模式为AT_MOST时如果:          * 子VIEw的宽或高为LayoutParams.MATCH_PARENT          * 那么:          * 子VIEw的size就是父容器在水平方向或垂直方向可用的最大空间值即size          * 子VIEw的mode也为MeasureSpec.AT_MOST          */         } 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;           resultMode = MeasureSpec.AT_MOST;          /**          * 当父容器的测量模式为AT_MOST时如果:          * 子VIEw的宽或高为LayoutParams.WRAP_CONTENT          * 那么:          * 子VIEw的size就是父容器在水平方向或垂直方向可用的最大空间值即size          * 子VIEw的mode也为MeasureSpec.AT_MOST          */         } else if (childDimension == LayoutParams.WRAP_CONTENT) {           // Child wants to determine its own size. It can't be           // bigger than us.           resultSize = size;           resultMode = MeasureSpec.AT_MOST;         }         break;        /**        * 第三种情况:        * 父容器的测量模式为UnspecIFIED        *        * 请注意两个系统常量:        * LayoutParams.MATCH_PARENT=-1        * LayoutParams.WRAP_CONTENT=-2        * 所以在此处的代码:        * childDimension >= 0 表示子VIEw的宽或高不是MATCH_PARENT和WRAP_CONTENT        */       case MeasureSpec.UnspecIFIED:         /**          * 当父容器的测量模式为UnspecIFIED时如果:          * 子VIEw的宽或高是一个精确的值,比如100px;          * 那么:          * 子VIEw的size就是childDimension          * 子VIEw的mode也为MeasureSpec.EXACTLY          */         if (childDimension >= 0) {           // Child wants a specific size... let him have it           resultSize = childDimension;           resultMode = MeasureSpec.EXACTLY;         /**          * 当父容器的测量模式为UnspecIFIED时如果:          * 子VIEw的宽或高为LayoutParams.MATCH_PARENT          * 那么:          * 子VIEw的size为0          * 子VIEw的mode也为MeasureSpec.UnspecIFIED          */         } else if (childDimension == LayoutParams.MATCH_PARENT) {           // Child wants to be our size... find out how big it should be           resultSize = 0;           resultMode = MeasureSpec.UnspecIFIED;         /**          * 当父容器的测量模式为UnspecIFIED时如果:          * 子VIEw的宽或高为LayoutParams.WRAP_CONTENT          * 那么:          * 子VIEw的size为0          * 子VIEw的mode也为MeasureSpec.UnspecIFIED          */         } else if (childDimension == LayoutParams.WRAP_CONTENT) {           // Child wants to determine its own size.... find out how big it should be           resultSize = 0;           resultMode = MeasureSpec.UnspecIFIED;         }         break;       }       return MeasureSpec.makeMeasureSpec(resultSize,resultMode);     }        } 

 如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

总结

以上是内存溢出为你收集整理的Android MeasureSpec的理解和源码的解析全部内容,希望文章能够帮你解决Android MeasureSpec的理解和源码的解析所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1144565.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存