Android MeasureSpec详解
简介
我们在自定义控件的时候经常要重写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 <size, mode> 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详解相关推荐
- 【转】Android菜单详解——理解android中的Menu--不错
原文网址:http://www.cnblogs.com/qingblog/archive/2012/06/08/2541709.html 前言 今天看了pro android 3中menu这一章,对A ...
- Android菜单详解——理解android中的Menu
前言 今天看了pro android 3中menu这一章,对Android的整个menu体系有了进一步的了解,故整理下笔记与大家分享. PS:强烈推荐<Pro Android 3>,是我至 ...
- Android LayoutInflater详解
Android LayoutInflater详解 在实际开发中LayoutInflater这个类还是非常有用的,它的作用类 似于findViewById().不同点是LayoutInflater是用来 ...
- android Fragments详解
android Fragments详解一:概述 android Fragments详解二:创建Fragment 转载于:https://my.oschina.net/liangzhenghui/blo ...
- android WebView详解,常见漏洞详解和安全源码(下)
上篇博客主要分析了 WebView 的详细使用,这篇来分析 WebView 的常见漏洞和使用的坑. 上篇:android WebView详解,常见漏洞详解和安全源码(上) 转载请注明出处:http ...
- android WebView详解,常见漏洞详解和安全源码(上)
这篇博客主要来介绍 WebView 的相关使用方法,常见的几个漏洞,开发中可能遇到的坑和最后解决相应漏洞的源码,以及针对该源码的解析. 由于博客内容长度,这次将分为上下两篇,上篇详解 WebView ...
- android子视图无菜单,Android 菜单详解
Android中菜单分为三种,选项菜单(OptionMenu),上下文菜单(ContextMenu),子菜单(SubMenu) 选项菜单 可以通过两种办法增加选项菜单,一是在menu.xml中添加,该 ...
- Android StateFlow详解
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/121913352 本文出自[赵彦军的博客] 文章目录 系列文章 一.冷流还是热流 S ...
- Android SharedFlow详解
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/121911675 本文出自[赵彦军的博客] 文章目录 系列文章 什么是SharedF ...
- Android菜单详解(三)——SubMenu和IconMenu
我们在上一篇介绍了如何在Android中创建和响应选项菜单,今天我们将探索子菜单和图标菜单. 子菜单Sub Menu 子菜单提供了一种自然的组织菜单项的方式,它被大量地运用在windows和其他OS的 ...
最新文章
- My deep learning reading list
- ili9341代码移植注意事项
- WHYZOJ-#60 工资(二分)
- javascript获取当前时间
- [css] 请描述margin边界叠加是什么及解决方案
- 95-230-010-源码-WordCount走读-概述
- Linux下QT创建项目错误处理
- pid算法matlab仿真程序和c程序,pid算法matlab仿真程序和c程序.doc
- linux的dhcp的安装,linux下DHCP的安装配置
- 信息化基础建设 总体结构
- 小红帽系统进入oracle,11G RAC 安装在红帽6上,grid跑root.sh报错
- Java学习电子书大全
- 51单片机直流电机调速
- 2019.8.29C++工作错误记录——Socket编程中出现ws2def.h文件“应输入标识符”或“重定义”问题(VS2015)
- Nginx主配置文件的优化-nginx主配置文件的优化
- html注册手机号验证,js正则表达式验证手机号码,用户名和邮箱
- macos 微信小助手
- 在线正则表达式测试器(JavaScript)
- DEEPCON: protein contact prediction using dilated convolutional neural networks with dropout
- 动态路由rip配置命令
热门文章
- ssdp协议搜索GB28181设备
- Linux操作系统知识点总结
- 值得收藏的UmiJS 教程
- kernel打印模块驱动加载时间
- 推荐一个简洁免费轻量级的思维导向图软件Blumind
- 旺旺怎么去服务器接收文件夹,xp系统下找到阿里旺旺安装路径文件夹的方法
- Python chardet模块
- python层次聚类法画图_原理+代码|详解层次聚类及Python实现
- CGB2005 JT-4(聚合工程 阿里数据源,配置项目启动项,EasyUI,树形结构,页面跳转restFul,JSON串说明,vo po,分页查询,叶子类目,Ajax嵌套,windows端口号占用)
- librdkafka------C kafka Client