博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android-MeasureSpec那些事
阅读量:5165 次
发布时间:2019-06-13

本文共 6515 字,大约阅读时间需要 21 分钟。

原文:http://tryenough.com/android-MeasureSpec

Android系统控件无法满足我们的需求,因此有必要自定义View。具体方法参见官方开发文档:

MeasureSpec的简介

MesureSpec可以理解为测量View大小的依据。它由一个32位的int值组成,前两位表示测量模式,后30位表示大小值

1240

测量模式(Mode)的类型有3种:UNSPECIFIED、EXACTLY 和

AT_MOST。

1240

原文:http://tryenough.com/android-MeasureSpec

Measure源码分析

public class MeasureSpec {        // 进位大小 = 2的30次方        // int的大小为32位,所以进位30位 = 使用int的32和31位做标志位        private static final int MODE_SHIFT = 30;                    // 运算遮罩:0x3为16进制,10进制为3,二进制为11        // 3向左进位30 = 11 00000000000(11后跟30个0)          // 作用:用1标注需要的值,0标注不要的值。因1与任何数做与运算都得任何数、0与任何数做与运算都得0        private static final int MODE_MASK  = 0x3 << MODE_SHIFT;            // UNSPECIFIED的模式设置:0向左进位30 = 00后跟30个0,即00 00000000000        // 通过高2位        public static final int UNSPECIFIED = 0 << MODE_SHIFT;                  // EXACTLY的模式设置:1向左进位30 = 01后跟30个0 ,即01 00000000000        public static final int EXACTLY = 1 << MODE_SHIFT;          // AT_MOST的模式设置:2向左进位30 = 10后跟30个0,即10 00000000000        public static final int AT_MOST = 2 << MODE_SHIFT;            /**          * makeMeasureSpec()方法          * 作用:根据提供的size和mode得到一个详细的测量结果,即measureSpec          **/             public static int makeMeasureSpec(int size, int mode) {                              return size + mode;              // measureSpec = size + mode;此为二进制的加法 而不是十进制            // 设计目的:使用一个32位的二进制数,其中:32和31位代表测量模式(mode)、后30位代表测量大小(size)            // 例如size=100(4),mode=AT_MOST,则measureSpec=100+10000...00=10000..00100              }                /**          * getMode()方法          * 作用:通过measureSpec获得测量模式(mode)          **/                public static int getMode(int measureSpec) {                               return (measureSpec & MODE_MASK);                  // 即:测量模式(mode) = measureSpec & MODE_MASK;                  // MODE_MASK = 运算遮罩 = 11 00000000000(11后跟30个0)                //原理:保留measureSpec的高2位(即测量模式)、使用0替换后30位                // 例如10 00..00100 & 11 00..00(11后跟30个0) = 10 00..00(AT_MOST),这样就得到了mode的值            }          /**          * getSize方法          * 作用:通过measureSpec获得测量大小size          **/                   public static int getSize(int measureSpec) {                               return (measureSpec & ~MODE_MASK);                  // size = measureSpec & ~MODE_MASK;                 // 原理类似上面,即 将MODE_MASK取反,也就是变成了00 111111(00后跟30个1),将32,31替换成0也就是去掉mode,保留后30位的size              }     }

原文:http://tryenough.com/android-MeasureSpec

MeasureSpec值的计算

子view的大小(MeasureSpec值)由父view的MeasureSpec值 和 子view的LayoutParams属性 共同决定,具体计算逻辑封装在getChildMeasureSpec()里.

/**  * 源码分析:getChildMeasureSpec()  * 作用:根据父视图的MeasureSpec & 布局参数LayoutParams,计算单个子View的MeasureSpec  * 注:子view的大小由父view的MeasureSpec值 和 子view的LayoutParams属性 共同决定  **/    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {           //参数说明         * @param spec 父view的详细测量值(MeasureSpec)          * @param padding view当前尺寸的的内边距和外边距(padding,margin)          * @param childDimension 子视图的布局参数(宽/高)            //父view的测量模式            int specMode = MeasureSpec.getMode(spec);                 //父view的大小            int specSize = MeasureSpec.getSize(spec);                           //通过父view计算出的子view = 父大小-边距(父要求的大小,但子view不一定用这个值)               int size = Math.max(0, specSize - padding);                        //子view想要的实际大小和模式(需要计算)              int resultSize = 0;              int resultMode = 0;                        //通过父view的MeasureSpec和子view的LayoutParams确定子view的大小              // 当父view的模式为EXACITY时,父view强加给子view确切的值           //一般是父view设置为match_parent或者固定值的ViewGroup             switch (specMode) {              case MeasureSpec.EXACTLY:                  // 当子view的LayoutParams>0,即有确切的值                  if (childDimension >= 0) {                      //子view大小为子自身所赋的值,模式大小为EXACTLY                      resultSize = childDimension;                      resultMode = MeasureSpec.EXACTLY;                  // 当子view的LayoutParams为MATCH_PARENT时(-1)                  } else if (childDimension == LayoutParams.MATCH_PARENT) {                      //子view大小为父view大小,模式为EXACTLY                      resultSize = size;                      resultMode = MeasureSpec.EXACTLY;                  // 当子view的LayoutParams为WRAP_CONTENT时(-2)                      } else if (childDimension == LayoutParams.WRAP_CONTENT) {                      //子view决定自己的大小,但最大不能超过父view,模式为AT_MOST                      resultSize = size;                      resultMode = MeasureSpec.AT_MOST;                  }                  break;                        // 当父view的模式为AT_MOST时,父view强加给子view一个最大的值。(一般是父view设置为wrap_content)              case MeasureSpec.AT_MOST:                  // 道理同上                  if (childDimension >= 0) {                      resultSize = childDimension;                      resultMode = MeasureSpec.EXACTLY;                  } else if (childDimension == LayoutParams.MATCH_PARENT) {                      resultSize = size;                      resultMode = MeasureSpec.AT_MOST;                  } else if (childDimension == LayoutParams.WRAP_CONTENT) {                      resultSize = size;                      resultMode = MeasureSpec.AT_MOST;                  }                  break;                        // 当父view的模式为UNSPECIFIED时,父容器不对view有任何限制,要多大给多大            // 多见于ListView、GridView              case MeasureSpec.UNSPECIFIED:                  if (childDimension >= 0) {                      // 子view大小为子自身所赋的值                      resultSize = childDimension;                      resultMode = MeasureSpec.EXACTLY;                  } else if (childDimension == LayoutParams.MATCH_PARENT) {                      // 因为父view为UNSPECIFIED,所以MATCH_PARENT的话子类大小为0                      resultSize = 0;                      resultMode = MeasureSpec.UNSPECIFIED;                  } else if (childDimension == LayoutParams.WRAP_CONTENT) {                      // 因为父view为UNSPECIFIED,所以WRAP_CONTENT的话子类大小为0                      resultSize = 0;                      resultMode = MeasureSpec.UNSPECIFIED;                  }                  break;              }              return MeasureSpec.makeMeasureSpec(resultSize, resultMode);          }

总结:

当父view的模式为UNSPECIFIED时(多见于ListView、GridView ),父容器不对view有任何限制,要多大给多大。此情况比较少见,这里不展开讨论,下面总结其余两种情况:

  • 1.子View指定大小值时:

Mode = MeasureSpec.EXACTLY;

Size = 指定的大小

  • 2.子View指定为MATCH_PARENT时:

Mode = 父View此时的模式;

Size = 父View的大小 - padding

  • 3.子View指定为WRAP_CONTENT时:

Mode = AT_MOST;

Size = 父View的大小 - padding, 即父View中剩余的空间

原文:http://tryenough.com/android-MeasureSpec

转载于:https://www.cnblogs.com/66it/p/10486047.html

你可能感兴趣的文章
基于FPGA实现的高速串行交换模块实现方法研究
查看>>
Java Scala获取所有注解的类信息
查看>>
delphi ,安装插件
查看>>
case when then的用法-leetcode交换工资
查看>>
11.28.cookie
查看>>
BeanShell简介
查看>>
python字符串操作
查看>>
不同程序语言的注释和变量要求
查看>>
语言基础(9):static, extern 和 inline
查看>>
ES5_03_Object扩展
查看>>
bzoj 2600: [Ioi2011]ricehub
查看>>
创建数据库,表
查看>>
工厂模式
查看>>
计算机网络基础知识
查看>>
C#里如何遍历枚举所有的项
查看>>
如何在键盘出现时滚动表格,以适应输入框的显示
查看>>
超级强大的鼠标手势工具
查看>>
常用Dockerfile举例
查看>>
jquery的ajax用法
查看>>
设计模式-策略模式(Strategy)
查看>>