MeasureSpec是View的宽高测量规则,它是由View的LayoutParams通过父布局施加的规则转换为对应的MeasureSpec而产生的,然后根据这个MeasureSpec来测量出View的具体宽高

一.MeasureSpec

MeasureSpec代表一个32位的int值,高2位代表SpecMode(测量模式),低30位代表SpecSize(某种测量模式下View的规格大小),具体可以参考MeasureSpec类的部分源码:

public static class MeasureSpec {private static final int MODE_SHIFT = 30;private static final int MODE_MASK  = 0x3 << MODE_SHIFT;//限定高2位的取值为[0, 3)/*** 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;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);}}/*** 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}*/@MeasureSpecModepublic static int getMode(int measureSpec) {//noinspection ResourceTypereturn (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);}
}

通过源码可以看到MeasureSpec将SpecMode和SpecSize打包为了一个int来避免额外的内存分配,所以也提供了解包方法getMode & getSize和打包方法makeMeasureSpec。并且决定测量模式的高2位int值被限制在了[0, 3),这就表明SpecMode可以有0、1、2三种取值并分别对应UNSPECIFIED、EXACTLY、AT_MOST:

EXACTLY

精确值模式,父布局已经测量出了View的实际大小,SpecSize就是View的尺寸,对应于LayoutParams中的match_parent或者直接指定具体宽高

AT_MOST

最大值模式,父布局指定了一个可用大小即SpecSize,View的大小不能大于这个值,对应于LayoutParams中的wrap_content

UNSPECIFIED

未指定模式,父布局不对View的尺寸有任何限制,View想多大就多大,通常在系统内部多次measure的时候才会用,一般情况下不需要关注

二.MeasureSpec和LayoutParams

View的MeasureSpec是由其自身的LayoutParams通过父布局MeasureSpec施加的规则转换为对应的MeasureSpec而产生的,来看一下父布局的measureChildWithMargins方法:

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

父布局拿到child的LayoutParams和自己宽高对应的MeasureSpec之后通过getChildMeasureSpec方法分别获取child宽高各自的测量规则MeasureSpec,最后调用measure方法测量child的实际大小。getChildMeasureSpec方法:

    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 them 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);}

入参中的padding表示父布局中已经被占用的空间,它包括父布局的内边距padding以及子View的外边距margin,所以子View的可用空间就是父布局的大小减去已经被占用的空间大小:

int specSize = MeasureSpec.getSize(spec);
int size = Math.max(0, specSize - padding);

子View具体是否要以这个可用空间作为自己的实际大小需要由父布局的SpecMode和子View的LayoutParams共同决定,上述代码中switch逻辑总结:

归结下逻辑就是:

. 如果子View固定死了宽/高,那么不管父布局采用哪种SpecMode,子View都采用精确值模式并使用固定的宽/高作为实际宽/高

. 如果子View的宽/高是match_parent,那么父布局采用精确值模式时子View也采用精确值模式并且使用父布局的可用空间宽/高作为实际宽/高

. 如果子View的宽/高是match_parent,那么父布局采用最大值模式时子View也采用最大值模式并且其实际宽/高不可以超过父布局的可用空间宽/高

. 如果子View的宽/高是wrap_content,那么不管父布局采用何种模式子View都会采用最大值模式并且其实际宽/高不可以超过父布局的可用空间宽/高

. UNSPECIFIED不需要关注,实际应用中几乎用不到

Android View的工作流程(一) 理解MeasureSpec相关推荐

  1. Android View的工作流程(二) measure过程

     一.View的measure过程 View的measure过程是由View的measure方法完成的,他是一个被final关键字修饰的方法,我们无法重写该方法,但是measure方法中会调用onMe ...

  2. android的构成和工作流程,分析Android中View的工作流程

    8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? 在分析View的工作流程时,需要先分析一个很重要的类,MeasureSpec.这个类在View的测量(Measure)过 ...

  3. Android之wifi工作流程

    Android Wifi的工作流程 一.WIFI工作相关部分 Wifi 网卡状态 1.    WIFI_STATE_DISABLED:WIFI网卡不可用 2.    WIFI_STATE_DISABL ...

  4. Android View的绘制流程

    View的绘制和事件处理是两个重要的主题,上一篇<图解 Android事件分发机制>已经把事件的分发机制讲得比较详细了,这一篇是针对View的绘制,View的绘制如果你有所了解,基本分为m ...

  5. Android View的绘制流程(1) -- 测量onMeasure

    鉴于是首篇讲解自定义view流程,之前也在网上搜了一些博主的博客看了看,都是大同小异,今天抽时间自己总结一下,分享一下自己的感悟,也算是一篇笔记. (本篇为开头篇,稍微讲述一下有关的东西) View的 ...

  6. 简单的Spring MVC入门程序,对于Spring mvc工作流程的理解,servlet标签和servlet-mapping 理解,视图解析器

    javaweb SpringMvc的组成:jsp,JavaBean,servlet 可以使用Spring所提供的功能 提供了前端控制器DispatcherServlet,不需要细化Servlet 执行 ...

  7. Android View的绘制流程简述 Android自定义View(一)

    1 Android的UI管理系统层级关系 如上图所示,这就是Android的UI管理系统的层级关系. 1.1 当一个应用启动的时候,会启动一个主Activity,然后Activity会创建出一个窗口系 ...

  8. android如何开发ui服务,Android UI-对Activity工作流程的理解(一)

    概述 在android studio创建一个新项目的时候,或者初学者在刚踏入android开发的时候,都会在首先创建一个MainActivity.根据一般的理解,Activity的就相当于一个界面的入 ...

  9. View 体系详解:View 的工作流程

    1.View 树的加载流程 当我们调用 startActivity() 方法的时候,会调用到 ActivityThread 中的 performLaunchActivity() 获取一个 Activi ...

  10. 对Android view/viewgroup事件分发的理解

    首先看看讲事件分发的博客: http://blog.csdn.net/xiaanming/article/details/21696315 和 http://www.csdn123.com/html/ ...

最新文章

  1. springboot RestTemplate httpclient
  2. python爬虫好学不_Python爬虫好学吗?
  3. DOM中严格区分大小写
  4. java 接口的访问权限_证明接口interface中定义的方法的访问权限为public
  5. 入侵Jasper以获取JSP页面的对象模型
  6. 多因素方差分析中预测因素的筛多_用回归来理解方差分析(二):两因素方差分析...
  7. 留学面试 计算机专业话题,英语面试_美国留学计算机专业详解_沪江英语
  8. D. Magic Breeding
  9. CCF201412-5 货物调度【费用流】(100分解题链接)
  10. 设计模式总结 —— 单例设计模式
  11. 地址修改验证TAR Oracle部署
  12. XINS 3.0 正式版发布,远程 API 调用规范
  13. android 分区 PT,Android:pt 、sp、dp之间的换算
  14. 2022年Web前端开发流程和学习路线
  15. python 文件名变量_如何将变量文件名传递给python ete?
  16. JSHOP2与ROS通信
  17. 路由器什么牌子好?消灭卡顿畅快吃鸡
  18. 斐讯n1做服务器性能,斐讯N1:系统配置优化
  19. C++基础知识点小结
  20. 程序员英语语法学习(2)认识词性(名词、动词、副词、形容词、冠词、介词、连词、语气词)

热门文章

  1. 连续变量的描述统计与SPSS实现
  2. [SUCTF 2018]GetShell 中文字符取反绕过
  3. c语言头文件下载大全,求C语言头文件下载?
  4. Verilog 实现四选一选择器
  5. hd530黑苹果硬解_黑苹果案例之—笔记本核显HD515_520_530_540_550
  6. 3dmax材质丢失插件_3dmax找回材质插件怎么用
  7. MVP架构模式简单示例
  8. 电路中各种地,数字地DGND、模拟地AGND、功率地PGND、电源地GND、交流地AGND、大地EGND的区别及处理
  9. 实验7 多个交换机虚拟局域网
  10. (新手必备)电子电路里面你必须知道的知识!!!