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

Android系统控件无法满足我们的需求,因此有必要自定义View。具体方法参见官方开发文档:http://developer.android.com/guide/topics/ui/custom-components.html

MeasureSpec的简介

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

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

原文: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与任何数做与运算都得0private 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 00000000000public static final int EXACTLY = 1 << MODE_SHIFT;  // AT_MOST的模式设置:2向左进位30 = 10后跟30个0,即10 00000000000public 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

Android-MeasureSpec那些事 1相关推荐

  1. Android实战--糗事

    一 .走进安卓世界 1 安卓发展历程 安卓 系统 发展历程 1.1 2008 9月 android 第一版本 1.5 2009年 4 月 30 Cupcake 纸杯蛋糕 拍摄 播放 上传youtube ...

  2. 我想谈谈关于Android面试那些事,一篇文章帮你解答

    开头 通常作为一个Android APP开发者,我们并不关心Android的源代码实现,不过随着Android开发者越来越多,企业在筛选Android程序员时越来越看中一个程序员对于Android底层 ...

  3. 程序员深度学习!我想谈谈关于Android面试那些事,附赠课程+题库

    想要成为一名优秀的Android开发,你需要一份完备的知识体系,在这里,让我们一起成长为自己所想的那样~. 25%的面试官会在头5分钟内决定面试的结果 60%的面试官会在头15分钟内决定面试的结果 一 ...

  4. 我想谈谈关于Android面试那些事,聪明人已经收藏了!

    前言 九月裸辞从长沙跑到上海,跑了一个月的面试,本月中旬终于拿到了爱奇艺的高级工程师offer. 做Android开发整4年有余,但是这一年才是最充实的,我花一年时间努力,送给了自己一个完美的蜕变! ...

  5. Iphone/Android开发囧事

    正在参与的项目是手机客户端(iphone/android)请求服务器的业务模式, 早上iphone同事问起我,说到"为什么wifi连接网络能从服务器192.168.1.****中获取数据,而 ...

  6. Android应用“今日事今日毕”发布了

    今日事今日毕,这是高效工作的最重原则. 没有什么能比从待办事项列表里划掉一些条目更让人觉得舒服的事了. 做为一个高效的人,您需要一个优秀的待办事项管理工具,一个优秀的待办事项列表可以帮助你更加高效的完 ...

  7. ios跟手android吧,这种事,人家还是喜欢用右手 | 涂手 #ios #Android

    在这个全民社交的年代,打着校园.婚恋.约会.图片.文学.艺术等title进行社交的产品越来越多.随着不同群体社交需求的不同,社交产品的脑洞也无限大.今天小编给大家推荐的就是一款小众确十分有趣的涂鸦社交 ...

  8. 安卓是java ios c_如何为Android和iOS使用相同的C ++代码?

    更新. 这个答案在我写完四年后很受欢迎,在这四年里,很多事情都发生了变化,所以我决定更新我的答案以更好地适应我们当前的现实. 答案的想法没有改变; 实施已经改变了一点. 我的英语也发生了变化,它已经有 ...

  9. Android Camera简单整理(一)-Camera Android架构(基于Q)

    Camera整体架构简单整理 一.Android Camera整体架构简述 1.1 Android Camera 基本分层 1.2 Android Camera工作大体流程 二. Camera App ...

  10. (4.6.31)Android Bitmap 详解

    文章目录 一.从相册加载一张图片 1.1 打开相册加载图片 1.2 根据Uri得到Bitmap 二.Bitmap 内存计算方式 2.1 density 和 densityDpi 2.2 getByte ...

最新文章

  1. 10个方法让程序员更加优秀
  2. subprocess模块
  3. TCP/IP协议概述
  4. 【语义分割】ICCV21_Mining Contextual Information Beyond Image for Semantic Segmentation
  5. 想在客户端脚本中引用CHECKBOXLIST中的CHECKBOX项?
  6. MongoDB中的索引操作
  7. 文档加载完成覆盖_在完成文档之前,作业尚未完成
  8. 直观讲解--RPC调用和HTTP调用的区别
  9. 最新emoji表情代码大全_由一个 emoji 引发的思考
  10. 用acdess制作html文件,使用ACDSee制作图片注释
  11. php 倒计时插件下载,jQuery自适应倒计时插件
  12. 电商(一) 创建订单业务流程
  13. python怎么导入包-python如何导入包
  14. 解决谷歌无法加载扩展程序
  15. 测绘资质属于工程资质吗?测绘资质和测量资质有什么区别?
  16. web service方法进行全文检索_软件架构分层方法论
  17. phpcms视频库KU6改为优酷简单上传
  18. 2020年AR(增强现实)最新发展趋势
  19. 致在研发路上努力奔跑的技术人
  20. 干货 | 想学习STEAM科学知识,必看这15个超赞的国外网站

热门文章

  1. KNN算法(10折交叉验证)
  2. 视频批量消重 短视频解析去水印在线
  3. jQuery菜鸟教程
  4. c语言 头文件 重复包含,C语言头文件如何避免重复包含
  5. 计算机页面排版的笔记,爱记笔记却懒得排版?这款笔记 App 为你准备了最实用的经典模板:格子笔记...
  6. python :alpha shapes 算法检测边界点
  7. RJ45墙上网线插座的线序与接法
  8. java移库数据同步,洗车管理系统会员管理+门店店务同步管理
  9. php houdini,houdini中文翻译.pdf
  10. html5 打开支付宝app,支付宝H5唤醒APP