Android MeasureSpec理解
MeasureSpec字面意思为测量的规格,他决定了view的测量过程
接下来探讨几个问题来学习MeauseSpec
1. MeasureSpec的构成
2. 如何创建MeasureSpec
3. 默认View的OnMeasure过程中对MeasureSpec的处理
一.MeasureSpec的构成
MeasureSpec代表一个32位的int值,前俩位代表SpecMode,后30位代表SpecSize.其中:SpecMode代表测量的模式,SpecSize值在某种测量模式下的规格大小。
共有三种测量模式:
1. EXACTLY: 父容器已经检测出子View所需要的精确大小,这个时候view的大小即为SpecSize的大小,他对应于布局参数中的MATCH_PARENT,或者精确大小值
2.AT_MOST: 父容器指定了一个大小,即SpecSize,子view的大小不能超过这个SpecSize的大小
3.UNSPECIFIED: 表示子View想多大都可以
二.如何创建MeasureSpec
MeasureSpec内部提供了创建MeasureSpec的方法:
public static int makeMeasureSpec(int size, int mode) {if (sUseBrokenMakeMeasureSpec) {return size + mode;} else {return (size & ~MODE_MASK) | (mode & MODE_MASK);}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
MeasureSpec代表一个32位的int值,前俩位代表SpecMode,后30位代表SpecSize.通过巧妙的位运算,即可通过MeasureSpec来得到SpecSize,SpecMode.
public static int getMode(int measureSpec) {return (measureSpec & MODE_MASK);}
- 1
- 2
- 3
public static int getSize(int measureSpec) {return (measureSpec & ~MODE_MASK);}
- 1
- 2
- 3
系统内部是通过MeasureSpec来对view进行测量。在view测量的时候,系统会将LayoutParams在父容器的约束下创建MeasureSpec.
view的顶级View为DecorView.他的MeasureSpec有窗口的尺寸与布局参数来决定。对于普通的View,他的MesureSpec由父容器的MeasureSpec与自身的布局参数来一起决定的。
DecorView的MeasureSpec创建过程如下:
private static int getRootMeasureSpec(int windowSize, int rootDimension) {int measureSpec;switch (rootDimension) {case ViewGroup.LayoutParams.MATCH_PARENT:// Window can't resize. Force root view to be windowSize.measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);break;case ViewGroup.LayoutParams.WRAP_CONTENT:// Window can resize. Set max size for root view.measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);break;default:// Window wants to be an exact size. Force root view to be that size.measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);break;}return measureSpec;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
其中windowSize为窗口的大小,即屏幕大小,rootDimension在DecorView中为MATCH_PARENT.故DecorView的MeasureSpec中的SpecSize为窗口大小,SpecMode的EXACTLY.
对于普通的子View来说,通过传入父容器的MeasureSpec,来计算子View的MeasureSpec。
通过measureChildWithMargins(View child,int parentWidthMeasureSpec, int widthUsed,int parentHeightMeasureSpec, int heightUsed);
在其内部在调用getChildMeasureSpec()方法来得到MeasureSpec.
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {int specMode = MeasureSpec.getMode(spec);int specSize = MeasureSpec.getSize(spec);int size = Math.max(0, specSize - padding);int resultSize = 0;int resultMode = 0;switch (specMode) {// Parent has imposed an exact size on uscase MeasureSpec.EXACTLY:if (childDimension >= 0) {resultSize = childDimension;resultMode = MeasureSpec.EXACTLY;} else if (childDimension == LayoutParams.MATCH_PARENT) {// Child wants to be our size. So be it.resultSize = size;resultMode = MeasureSpec.EXACTLY;} 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;// Parent has imposed a maximum size on uscase MeasureSpec.AT_MOST:if (childDimension >= 0) {// Child wants a specific size... so be itresultSize = childDimension;resultMode = MeasureSpec.EXACTLY;} 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;} 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;// Parent asked to see how big we want to becase MeasureSpec.UNSPECIFIED:if (childDimension >= 0) {// Child wants a specific size... let him have itresultSize = childDimension;resultMode = MeasureSpec.EXACTLY;} else if (childDimension == LayoutParams.MATCH_PARENT) {// Child wants to be our size... find out how big it should// beresultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;resultMode = MeasureSpec.UNSPECIFIED;} else if (childDimension == LayoutParams.WRAP_CONTENT) {// Child wants to determine its own size.... find out how// big it should beresultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;resultMode = MeasureSpec.UNSPECIFIED;}break;}return MeasureSpec.makeMeasureSpec(resultSize, resultMode);}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
大体过程如下:
一:如果父容器的SpecMode为EXACTLY,那么在判断子view自己的布局参数.
1.如果为具体数值,或者MATCH_PARENT时候,那么子view的SpecMode为EXACTLY,SpecSize为父容器的SpecSize,为具体指时,SpecSize为具体值。
2.如果为WRAP_CONTENT时,那么子View的SpecMode为AT_MOST,SpecSize为父容器的SpecSize.表示子View最大不会超过父容器
二:如果父容器的SpecMode为AT_MOST时:
1.如果子View的测量规格为MATCH_PARENT,或者WRAP_CONTENT时,那么子View的SpecMode为AT_MOST,SpecSize为父容器的SpecSize.
2.如果子View的测量规格为精确值时,那么子View的测量规格为EXACTLY,SpecSize为具体的值。
上述的判断过程均为系统的判断过程,了解这些有益于得知开发过程中出现的情况的原因。
三. 默认View的OnMeasure过程中对MeasureSpec的处理
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));}
- 1
- 2
- 3
- 4
getDefaultSize的方法实现如下:
public static int getDefaultSize(int size, int measureSpec) {int result = size;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);switch (specMode) {case MeasureSpec.UNSPECIFIED:result = size;break;case MeasureSpec.AT_MOST:case MeasureSpec.EXACTLY:result = specSize;break;}return result;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
从上面的代码中可以看到默认onMeasure()方法中的判断逻辑为:
在SpecMode为AT_MOST,EXACTLY时,测量的大小都为SpecSize.
这里我举一个列子,比方说我们在activity的布局文件中自定义了一个View,把这个view的宽高都设置为WRAP_CONTNET时,这时我们会发现这个view充满了整个屏幕。发生这样的原因是正是上面代码逻辑判断的结果。首先这个字View的父容器为DecorView中的一个ViewGroup,他内部是有一个FrameLayout的布局。这个父容器的SpecSize为整个屏幕的大小。现在看子View,子view的布局参数为wrap_content,那么子View的MeasureSpec中的SpecSize为整个屏幕,SpecMode为AT_MOST,在getDefaultSize中,当测量模式AT_MOST,或者MATCH_PARENT时,都是直接把SpecSize的值给返回了,而这个SpecSize的值正好是整个屏幕,所以出现是view不管是设置为MATCH_PARENT,还是WRAP_CONTENT都是充满了整个屏幕
<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/markdown_views-ea0013b516.css"></div>
Android MeasureSpec理解相关推荐
- Android深入理解Fragment
Fragment 目录 思维导图 概述 设计原因 基本使用 xml 声明 代码设置 添加没有 UI 的 fragment 生命周期 管理 Fragment 和执行事务 与 Activity 通信 常见 ...
- Android 深入理解 ANR 触发原理:Service
一.概述 ANR(Application Not responding),是指应用程序未响应,Android系统对于一些事件需要在一定的时间范围内完成,如果超过预定时间能未能得到有效响应或者响应时间过 ...
- Android深入理解文字绘制:FontMetrics字体测量及其TextPaint介绍
文章目录 TextPaint介绍 一.FontMetrics 1.1 理论知识 1.2 代码验证 1.3 fontMetrics中的变量和文字的size.typeface有关 1.4 绘制居中屏幕的文 ...
- android:layout_with=,android – 难以理解layout_alignWithParentIfMissing
这仅适用于使用RelativeLayout时. 如果您将元素设置为一个其他元素,则表示该元素位于该元素的左侧. 但是如果这个元素会丢失,因为你删除它,例如它将与父对齐. 举个例子 android:la ...
- 【Android个人理解(八)】跨应用调用不同组件的方法
如果情景: 创建两个应用appA和appB,appA包括一个Service,此Service有一个堵塞方法每隔10秒钟产生一个随机数字,例如以下: public int getRandomInt(){ ...
- Android深入理解Context(三)Context完全解析
1· Context类型 我们知道,Android应用都是使用Java语言来编写的,那么大家可以思考一下,一个Android程序和一个Java程序,他们最大的区别在哪里?划分界限又是什么呢?其实简单点 ...
- Android targetsdkversion理解
一.Android gradle中常见的版本配置 compileSdkVersion 代表着编译的时候,会采用该api的规范进行代码检查和警告,但是并不会编译进apk中. targetSdkVersi ...
- Android 深入理解Android中的自定义属性
转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/45022631: 本文出自:[张鸿洋的博客] 1.引言 对于自定义属性,大家肯定 ...
- intent在android中的作用,Android开发理解Intent的用途
1.Intent的定义 Intent这个单词的意思就是"意图,目的,意向",Intent是一种运行时绑定(runtime binding)机制,它能在程序运行的过程中连接两个不同的 ...
- android keystore作用,Android KeyStore理解及簽名
Android簽名概述 我們已經知道的是:Android對每一個Apk文件都會進行簽名,在Apk文件安裝時,系統會對其簽名信息進行比對,判斷程序的完整性,從而決定該Apk文件是否可以安裝,在一定程度上 ...
最新文章
- Python os.path路径模块中的操作方法总结
- c语言在键盘输入abc回车,C语言期末考试试卷子商务1111、21.doc
- java中spring的web支持nio,Spring WebClient NIO功能和问题域,与Spring Webflux一起使用
- iic总线从机仲裁_IIC协议底层原理超详细解析!示波器,逻辑分析仪多图预警
- RabbitMQ学习笔记:安装环境
- 新型APT组织正在攻击全球的政府实体
- 05-Servlet与内部加载机制(part1)
- 苹果Mac强大的采样器音源软件:Native Instruments Kontakt
- js实现的万年历显示
- 关于select和option下拉框样式问题
- 如何给PDF文件加密?PDF文件加密操作步骤来了
- 用office toll plus 安装office2019 vol版
- Excel读写合集:Excel读写小白从不知所措到轻松上手
- oracle sysdate 月份,如何将oracle中的sysdate月份值转换为数字?
- 03-多线程下载网图
- 基于神经网络的预测控制,神经网络预测系统应用
- 简谈python正则表达式
- MySQL 中的系统库之sys 系统库
- 8 Hibernate:关联映射(Associations)
- 【综合应用】基础PLS-SEM模型STATA实战
热门文章
- 一键清除windows远程桌面访问痕迹bat脚本
- 使用谷歌浏览器出现插件未就绪以及CLodop云打印服务(localhost本地)未安装启动!请下载安装包!
- 最简单的文件加密工具(完全免费)
- 如何读代码?读代码的利器---FreeMind
- efs+pro+for+三星android设备,【极光ROM】-【三星S8/S8+ G9550/G9500】-【V30.0 Android-PIE-TL2】...
- 一加6android9玩飞车掉,解锁新速度:一加6T深度评测
- 华为手机助手(PC)无法连接的通用解决方案
- 2020年ROS机器人操作系统用户官方调查
- Mujoco有限状态机以及轨迹追踪
- 北醒TF雷达在飞控F4 上的应用