MeasureSpec详解
1.MeasureSpec简介
- MeasureSpec封装了从父级传递给子级的布局要求。 每个MeasureSpec代表宽度或高度的要求。
- MeasureSpecs实现为32位的int,由size和mode组成,高2位代表mode,低30位代表size,它通过将mode和size打包成一个int值来减少对象内存分配,并提供打包和解包的方法。
- mode分类:
- UNSPECIFIED:父容器不对View有任何限制,给它想要的任何尺寸。一般用于系统内部,表示一种测量状态。
- EXACTLY:父容器已经检测出view的精确大小,这时候view的大小就是size所指定的值。它对应于LayoutParams中的match_parent和具体数值两种模式。
- AT_MOST:父容器指定了一个可用大小,即size,子view的大小不能大于这个值,具体值要看vew的实现。它对应于LayoutParams中的wrap_content。
public static class MeasureSpec {private static final int MODE_SHIFT = 30;private static final int MODE_MASK = 0x3 << MODE_SHIFT;/** @hide */@IntDef({UNSPECIFIED, EXACTLY, AT_MOST})@Retention(RetentionPolicy.SOURCE)public @interface MeasureSpecMode {}public static final int UNSPECIFIED = 0 << MODE_SHIFT;public static final int EXACTLY = 1 << MODE_SHIFT;public static final int AT_MOST = 2 << MODE_SHIFT;public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,@MeasureSpecMode int mode) {if (sUseBrokenMakeMeasureSpec) {return size + mode;} else {return (size & ~MODE_MASK) | (mode & MODE_MASK);}}public static int makeSafeMeasureSpec(int size, int mode) {if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) {return 0;}return makeMeasureSpec(size, mode);}@MeasureSpecModepublic static int getMode(int measureSpec) {//noinspection ResourceTypereturn (measureSpec & MODE_MASK);}public static int getSize(int measureSpec) {return (measureSpec & ~MODE_MASK);}static int adjust(int measureSpec, int delta) {final int mode = getMode(measureSpec);int size = getSize(measureSpec);if (mode == UNSPECIFIED) {// No need to adjust size for UNSPECIFIED mode.return makeMeasureSpec(size, UNSPECIFIED);}size += delta;if (size < 0) {Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size +") spec: " + toString(measureSpec) + " delta: " + delta);size = 0;}return makeMeasureSpec(size, mode);}}
2.MeasureSpec与LayoutParams的关系
普通View的Measure参数是由父容器传递而来,这里我们可以看下ViewGroup的measureChildWithMargins方法:
/*** @param child 要测量的子view* @param parentWidthMeasureSpec 该容器对子view的宽度要求* @param widthUsed 父级水平使用的额外空间(可能是父级的其他子级),可以理解为已经被占用的空间* @param parentHeightMeasureSpec 该容器对子view的高度要求* @param heightUsed 父级垂直使用的额外空间(可能是父级的其他子级)*/protected void measureChildWithMargins(View child,int parentWidthMeasureSpec, int widthUsed,int parentHeightMeasureSpec, int heightUsed) {final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin+ widthUsed, lp.width);final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin+ heightUsed, lp.height);child.measure(childWidthMeasureSpec, childHeightMeasureSpec);}
可以看到子View的测量参数是由getChildMeasureSpec方法得到的,父容器对子View的测量要求、父容器的Padding、子View的margin、父容器的已占空间最终算出了子View的MeasureSpec
/*** @param spec 该容器的测量要求* @param padding 可以简单理解为子view和该容器之间的间隔,由多个值决定* @param childDimension 子view的期望值,即子view的LayoutParams的宽高*/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;}//noinspection ResourceTypereturn MeasureSpec.makeMeasureSpec(resultSize, resultMode);}
上述代码可以简单翻译成下面这个图表:
child\parent | EXACTLY | AT_MOST | UNSPECIFIED |
---|---|---|---|
具体尺寸 | EXACTLY、childSize | EXACTLY、childSize | EXACTLY、childSize |
match_parent | EXACTLY、parentSize | AT_MOST、parentSize | UNSPECIFIED、SDK<23?0:parentSize |
wrap_content | AT_MOST、parentSize | AT_MOST、parentSize | UNSPECIFIED、SDK<23?0:parentSize |
作者:风少侠
链接:https://www.jianshu.com/p/7e48efe54f2c
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
MeasureSpec详解相关推荐
- ANDROID自定义视图——onMeasure流程,MeasureSpec详解
简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量--onMeasure():决定View的大小 2.布局--onLayout():决定View在ViewGroup中的位置 3. ...
- View系列 (三) — Measure 流程详解
Measure 流程详解 一.概述 二.单一 View 的测量流程 1. 流程图 2. 源码分析 三.ViewGroup 的测量流程 1. 流程图 2. 源码分析 一.概述 测量过程分为 View的m ...
- Android中measure过程、WRAP_CONTENT详解以及 xml布局文件解析流程浅析
转自:http://www.uml.org.cn/mobiledev/201211221.asp 今天,我着重讲解下如下三个内容: measure过程 WRAP_CONTENT.MATCH_PAREN ...
- Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(下)
本文原创, 转载请注明出处:http://blog.csdn.net/qinjuning 上篇文章<<Android中measure过程.WRAP_CONTENT详解以及xml布局文 ...
- android标尺自定义view,android尺子的自定义view——RulerView详解
项目中用到自定义尺子的样式: 原效果为 因为跟自己要使用的view稍有不同 所以做了一些修改,修改的注释都放在代码中了,特此记录一下. 首先是一个自定义View: public class RuleV ...
- Andoid自定义View的OnMeasure详解和自定义属性
一,OnMeasure详解 Android开发中偶尔会用到自定义View,一般情况下,自定义View都需要继承View类的onMeasure方法,那么,为什么要继承onMeasure()函数呢?什么情 ...
- android 截图 listview,Android屏幕及view的截图实例详解
Android屏幕及view的截图实例详解 屏幕可见区域的截图 整个屏幕截图的话可以用View view = getWindow().getDecorView(); public static Bit ...
- View绘制详解(三),扒一扒View的测量过程
所有东西都是难者不会,会者不难,Android开发中有很多小伙伴觉得自定义View和事件分发或者Binder机制等是难点,其实不然,如果静下心来花点时间把这几个技术点都研究一遍,你会发现其实这些东西都 ...
- java 嵌套listview_ListView嵌套GridView使用详解
MainActivity如下: package cn.testlistviewandgridview; import java.util.ArrayList; import java.util.Has ...
- Android measure方法详解
1. MeasureSpec类 MeasureSpec用来计算子视图的大小,有三种类型,UNSPECIFIED.EXACTLY和AT_MOST. UNSPECIFIED表示未定义,即父控件未做限制,可 ...
最新文章
- 网络推广——网络推广专员是如何进行图像优化的?
- Spring MVC 成员变量 request 线程安全问题的讨论
- 爬虫.之登陆及动态网页的抓取
- winform B窗體調用A窗體的DATAGRIDVIEW刷新
- java.Net.UnknownHostException异常
- c语言怎样编写图形,「分享」C语言如何编写图形界面
- CCF NOI1026 表演打分
- 小程序wafer2操作数据库
- 阶段3 3.SpringMVC·_01.SpringMVC概述及入门案例_05.入门程序之入门代码编写
- linux 查看设备 usb设备驱动程序,Linux USB设备驱动程序未被探测
- Mac SecureCRT 8.0.2破解版
- 2022-2028年全球及中国ODM智能手机行业投资前景分析
- html5画布获取位置,html5画布绘制位置不正确(html5 canvas drawing position not correct)
- 【游戏中的算法】取火柴游戏算法
- 深信服防火墙设备故障机的更换方法
- 咸鱼前端—CSS选择器
- 高德API支持WMS服务器,GCJ02-Correct
- 使用十六进制设置颜色
- sed Linux并发报错,完美解决mac环境使用sed修改文件出错的问题
- Win10 LTSC 离线安装 Microsoft 照片应用
热门文章
- PHP打出来的数字和成语,php批量将词语 成语 导入数据库
- vivado下载地址和ISE下载地址
- 计算机驱动程序检测,检测到计算机制造商图形驱动程序对于显卡驱动程序
- 考上一级建造师很牛吗?让我从一个屌丝技术员到项目经理
- sle4442,sle4428解
- LTE物理层一些基本概念
- php eof记录指针,关于ASP eof与bof 区别分析
- 计算机会考ppt考试,信息技术会考Powerpoint复习要点
- c语言课程设计报告书模板,C语言课程设计报告模板(最终版).doc
- 火焰识别python_OpenCV_火焰检测——完整代码