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详解相关推荐

  1. ANDROID自定义视图——onMeasure流程,MeasureSpec详解

    简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量--onMeasure():决定View的大小 2.布局--onLayout():决定View在ViewGroup中的位置 3. ...

  2. View系列 (三) — Measure 流程详解

    Measure 流程详解 一.概述 二.单一 View 的测量流程 1. 流程图 2. 源码分析 三.ViewGroup 的测量流程 1. 流程图 2. 源码分析 一.概述 测量过程分为 View的m ...

  3. Android中measure过程、WRAP_CONTENT详解以及 xml布局文件解析流程浅析

    转自:http://www.uml.org.cn/mobiledev/201211221.asp 今天,我着重讲解下如下三个内容: measure过程 WRAP_CONTENT.MATCH_PAREN ...

  4. Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(下)

       本文原创, 转载请注明出处:http://blog.csdn.net/qinjuning 上篇文章<<Android中measure过程.WRAP_CONTENT详解以及xml布局文 ...

  5. android标尺自定义view,android尺子的自定义view——RulerView详解

    项目中用到自定义尺子的样式: 原效果为 因为跟自己要使用的view稍有不同 所以做了一些修改,修改的注释都放在代码中了,特此记录一下. 首先是一个自定义View: public class RuleV ...

  6. Andoid自定义View的OnMeasure详解和自定义属性

    一,OnMeasure详解 Android开发中偶尔会用到自定义View,一般情况下,自定义View都需要继承View类的onMeasure方法,那么,为什么要继承onMeasure()函数呢?什么情 ...

  7. android 截图 listview,Android屏幕及view的截图实例详解

    Android屏幕及view的截图实例详解 屏幕可见区域的截图 整个屏幕截图的话可以用View view = getWindow().getDecorView(); public static Bit ...

  8. View绘制详解(三),扒一扒View的测量过程

    所有东西都是难者不会,会者不难,Android开发中有很多小伙伴觉得自定义View和事件分发或者Binder机制等是难点,其实不然,如果静下心来花点时间把这几个技术点都研究一遍,你会发现其实这些东西都 ...

  9. java 嵌套listview_ListView嵌套GridView使用详解

    MainActivity如下: package cn.testlistviewandgridview; import java.util.ArrayList; import java.util.Has ...

  10. Android measure方法详解

    1. MeasureSpec类 MeasureSpec用来计算子视图的大小,有三种类型,UNSPECIFIED.EXACTLY和AT_MOST. UNSPECIFIED表示未定义,即父控件未做限制,可 ...

最新文章

  1. 网络推广——网络推广专员是如何进行图像优化的?
  2. Spring MVC 成员变量 request 线程安全问题的讨论
  3. 爬虫.之登陆及动态网页的抓取
  4. winform B窗體調用A窗體的DATAGRIDVIEW刷新
  5. java.Net.UnknownHostException异常
  6. c语言怎样编写图形,「分享」C语言如何编写图形界面
  7. CCF NOI1026 表演打分
  8. 小程序wafer2操作数据库
  9. 阶段3 3.SpringMVC·_01.SpringMVC概述及入门案例_05.入门程序之入门代码编写
  10. linux 查看设备 usb设备驱动程序,Linux USB设备驱动程序未被探测
  11. Mac SecureCRT 8.0.2破解版
  12. 2022-2028年全球及中国ODM智能手机行业投资前景分析
  13. html5画布获取位置,html5画布绘制位置不正确(html5 canvas drawing position not correct)
  14. 【游戏中的算法】取火柴游戏算法
  15. 深信服防火墙设备故障机的更换方法
  16. 咸鱼前端—CSS选择器
  17. 高德API支持WMS服务器,GCJ02-Correct
  18. 使用十六进制设置颜色
  19. sed Linux并发报错,完美解决mac环境使用sed修改文件出错的问题
  20. Win10 LTSC 离线安装 Microsoft 照片应用

热门文章

  1. PHP打出来的数字和成语,php批量将词语 成语 导入数据库
  2. vivado下载地址和ISE下载地址
  3. 计算机驱动程序检测,检测到计算机制造商图形驱动程序对于显卡驱动程序
  4. 考上一级建造师很牛吗?让我从一个屌丝技术员到项目经理
  5. sle4442,sle4428解
  6. LTE物理层一些基本概念
  7. php eof记录指针,关于ASP eof与bof 区别分析
  8. 计算机会考ppt考试,信息技术会考Powerpoint复习要点
  9. c语言课程设计报告书模板,C语言课程设计报告模板(最终版).doc
  10. 火焰识别python_OpenCV_火焰检测——完整代码