简介

我们在自定义控件的时候经常要重写View的onMeasure方法,onMeasure方法有两个int类型的参数,这两个参数就是MeasureSpec,这两个参数可不是普通的int数值,里面包含了mode和size两个信息,一个int有32位二进制,用高2位表示mode,低30位表示size,这样在一个int里面包含两个数值信息的设计,是为了减少对象的创建和内存的分配

onMeasure()方法用来测量空间的宽高,方法中的MeasureSpec参数由控件的父布局传入,是父View对子View的宽高的约束。

要注意onMeasure()方法的参数类型是int而不是MeasureSpec,MeasureSpec只是一个工具类,用来打包和拆包mode和size

源码

在讲解前,我建议先看下MeasureSpec的源码和源码的注释,源码很简单,注释里也讲的很清楚

为了更便于阅读,以下源码是比较早的安卓版本Android 4.1(Jelly Bean),API16

    /*** 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 {private static final int MODE_SHIFT = 30;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.*/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.*/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.*/public static final int AT_MOST     = 2 << MODE_SHIFT;/*** 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>** @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) {return 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);}/*** 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 ");elsesb.append(mode).append(" ");sb.append(size);return sb.toString();}}

mode

上面说过MeasureSpec的高两位表示mode,mode有三种类型

UNSPECIFIED:父View对子View没有任何限制,子View的宽高想多大就多大

EXACTLY:父View已经替子View确定了大小,不管子View要多大都不行

AT_MOST:子View要多大就多大,但是不能超过上限

掩码Mask和mode常量

在上面的源码中可以看到三种mode的定义及mask的定义,可以再看一下

        private static final int MODE_SHIFT = 30;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.*/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.*/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.*/public static final int AT_MOST     = 2 << MODE_SHIFT;

MODE_SHIFT=30,这个常量下面会用到,做一些位移的操作

MODE_MASK就是掩码,0x3就是二进制0b11,向左位移30位后就是0b11000000000000000000000000000000,这个就可以作为mode的掩码,和int类型的MeasureSpec做位与运算就可以得到mode的值,后面会做详细介绍

UNSPECIFIED模式的值为0,0 << MODE_SHIFT位移运算后其实值还是零,0b00000000000000000000000000000000,高二位为00

EXACTLY模式的值为1 << MODE_SHIFT,也就是1左移30位,用二进制表示为0b01000000000000000000000000000000,高二位为01

int AT_MOST模式的值为2 << MODE_SHIFT,2用二进制表示为0b10,也就是0b10左移30位,用二进制表示为0b10000000000000000000000000000000,高二位为10

组装mode和size

MeasureSpec是一个int类型的数值,由mode和size组成,高二位表示mode,低30位表示size

mode必须为UNSPECIFIED,AT_MOST,EXACTLY三种类型的一种

方法很简单,就是把参数size和mode相加就完事了

比如:

0b01000000000000000000000000000000,mode为EXACTLY

0b00000000000000000000000000000011,size为3

0b01000000000000000000000000000011,这就是相加后的结果measure specification

代码如下所示,非常简单

        /*** 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>** @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) {return size + mode;}

解析mode

解析MeasureSpec中的mode也是很简单,保留高2位,其余低30位置0就可以了

掩码MODE_MASK值为0b11000000000000000000000000000000,将MeasureSpec和掩码MODE_MASK做位与运算,就可以保留高2位,其余低30位置零,得到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);}

解析size

解析size和解析mode的方法类似,只是把高2位置零,其余低30位保留

先把掩码MODE_MASK做按位取反,得到0b00111111111111111111111111111111,这个就是size的掩码,再把该掩码和MeasureSpec做位与运算,就得到size的值

size的单位是px

        /*** 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);}

格式化打印输出

这个方法就是把MeasureSpec格式化下打印输出,可以看该MeasureSpec包含的mode和size信息

格式为"MeasureSpec: MODE SIZE",比如"MeasureSpec: EXACTLY 100"

        /*** 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 ");elsesb.append(mode).append(" ");sb.append(size);return sb.toString();}
												

Android MeasureSpec详解相关推荐

  1. 【转】Android菜单详解——理解android中的Menu--不错

    原文网址:http://www.cnblogs.com/qingblog/archive/2012/06/08/2541709.html 前言 今天看了pro android 3中menu这一章,对A ...

  2. Android菜单详解——理解android中的Menu

    前言 今天看了pro android 3中menu这一章,对Android的整个menu体系有了进一步的了解,故整理下笔记与大家分享. PS:强烈推荐<Pro Android 3>,是我至 ...

  3. Android LayoutInflater详解

    Android LayoutInflater详解 在实际开发中LayoutInflater这个类还是非常有用的,它的作用类 似于findViewById().不同点是LayoutInflater是用来 ...

  4. android Fragments详解

    android Fragments详解一:概述 android Fragments详解二:创建Fragment 转载于:https://my.oschina.net/liangzhenghui/blo ...

  5. android WebView详解,常见漏洞详解和安全源码(下)

    上篇博客主要分析了 WebView 的详细使用,这篇来分析 WebView 的常见漏洞和使用的坑.  上篇:android WebView详解,常见漏洞详解和安全源码(上)  转载请注明出处:http ...

  6. android WebView详解,常见漏洞详解和安全源码(上)

    这篇博客主要来介绍 WebView 的相关使用方法,常见的几个漏洞,开发中可能遇到的坑和最后解决相应漏洞的源码,以及针对该源码的解析.  由于博客内容长度,这次将分为上下两篇,上篇详解 WebView ...

  7. android子视图无菜单,Android 菜单详解

    Android中菜单分为三种,选项菜单(OptionMenu),上下文菜单(ContextMenu),子菜单(SubMenu) 选项菜单 可以通过两种办法增加选项菜单,一是在menu.xml中添加,该 ...

  8. Android StateFlow详解

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/121913352 本文出自[赵彦军的博客] 文章目录 系列文章 一.冷流还是热流 S ...

  9. Android SharedFlow详解

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/121911675 本文出自[赵彦军的博客] 文章目录 系列文章 什么是SharedF ...

  10. Android菜单详解(三)——SubMenu和IconMenu

    我们在上一篇介绍了如何在Android中创建和响应选项菜单,今天我们将探索子菜单和图标菜单. 子菜单Sub Menu 子菜单提供了一种自然的组织菜单项的方式,它被大量地运用在windows和其他OS的 ...

最新文章

  1. My deep learning reading list
  2. ili9341代码移植注意事项
  3. WHYZOJ-#60 工资(二分)
  4. javascript获取当前时间
  5. [css] 请描述margin边界叠加是什么及解决方案
  6. 95-230-010-源码-WordCount走读-概述
  7. Linux下QT创建项目错误处理
  8. pid算法matlab仿真程序和c程序,pid算法matlab仿真程序和c程序.doc
  9. linux的dhcp的安装,linux下DHCP的安装配置
  10. 信息化基础建设 总体结构
  11. 小红帽系统进入oracle,11G RAC 安装在红帽6上,grid跑root.sh报错
  12. Java学习电子书大全
  13. 51单片机直流电机调速
  14. 2019.8.29C++工作错误记录——Socket编程中出现ws2def.h文件“应输入标识符”或“重定义”问题(VS2015)
  15. Nginx主配置文件的优化-nginx主配置文件的优化
  16. html注册手机号验证,js正则表达式验证手机号码,用户名和邮箱
  17. macos 微信小助手
  18. 在线正则表达式测试器(JavaScript)
  19. DEEPCON: protein contact prediction using dilated convolutional neural networks with dropout
  20. 动态路由rip配置命令

热门文章

  1. ssdp协议搜索GB28181设备
  2. Linux操作系统知识点总结
  3. 值得收藏的UmiJS 教程
  4. kernel打印模块驱动加载时间
  5. 推荐一个简洁免费轻量级的思维导向图软件Blumind
  6. 旺旺怎么去服务器接收文件夹,xp系统下找到阿里旺旺安装路径文件夹的方法
  7. Python chardet模块
  8. python层次聚类法画图_原理+代码|详解层次聚类及Python实现
  9. CGB2005 JT-4(聚合工程 阿里数据源,配置项目启动项,EasyUI,树形结构,页面跳转restFul,JSON串说明,vo po,分页查询,叶子类目,Ajax嵌套,windows端口号占用)
  10. librdkafka------C kafka Client