/**
* host.measure()会 调 用 到View类 的 measure()函数,该函数然后回调onMeasure()。在一般情况下,
* host对象是一个ViewGroup实例,该ViewGroup会重载onMeasure(),当然如果host没有重载onMeasure(),
* 则会执行View类中默认的onMeasure()。在一般情况下,程序员需要在重载的onMeaSure()函数中逐一
* 对 所 包 含 的 子 视 图 执 行 measureO操 作 , 为 了 简 化 程 序 设 计 , ViewGroup类 内 部 提 供 了
* measureChildWithMargin()函数,该函数内部会进行一定的参数调整,然后再次调用子视图的measure()
* 函 数 , 这 就 又 调 用 到 onMeasure()。 如 果 子 视 图 是 一 个 ViewGroup实 例 , 则 应 该 继 续 调 用
* measureChildWithMarginO对下一层的子视图进行measure操作;如果子视图就是一个具体的View实例,
* 则 在 重 载 的onMeasures()函数内部就不需要再次调用measureChildWithMargins(),从 而 一 次 measure()
* 过程结束
*
* 在该函数定义中, final关键字说明,该函数是不能被重载的,即 View系统定义的这个measure框
* 架不能被修改。参数 widthMeasureSpec 和 heightMeaureSpec 分别对应宽和高的 measureSpec,measureSpec
* 是 一 个int型值,当父视图对子视图进行measure操作时,会调用子视图的meaSUre()函数,该参数的意
* 思是父视图所提供的measure的 “规格”,因为父视图最终为子视图提供的“窗口”大小是由父视图和
* 子视图共同决定的。 该值由高32位 和 低16位组成,其中高32位保存的是specMode,低 16位 为specSize。
* specMode有三种,分别如下。
* • MeasureSpec.EXACTLY: “确定的”,意思是说,父视图希望子视图的大小应该是specSize中指
* 定的。在一般情况下,View的设计者应该遵守该指示,将View的measuredHeigth和measuredWidth
* 设置成指定的值,当然,也可以不遵守。
* • MeasureSpec .AT_MOST: “最多”,意思是说,子视图的大小最多是specSize中指定的值。在一
* 般情况下, View的设计者应该尽可能小地设置视图的大小,并且不能超过specSize,当然,也
* 可以超过specSize。
* • MeasureSpec .UNSPECIFIED: “没有限制”,此 时 View的设计者可以根据自身的特性设置视图
* 的大小。
*/

    public final void measure(int widthMeasureSpec, int heightMeasureSpec) {if ((mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT ||widthMeasureSpec != mOldWidthMeasureSpec ||heightMeasureSpec != mOldHeightMeasureSpec) {// first clears the measured dimension flagmPrivateFlags &= ~MEASURED_DIMENSION_SET;if (ViewDebug.TRACE_HIERARCHY) {ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_MEASURE);}// measure ourselves, this should set the measured dimension flag backonMeasure(widthMeasureSpec, heightMeasureSpec);// flag not set, setMeasuredDimension() was not invoked, we raise// an exception to warn the developerif ((mPrivateFlags & MEASURED_DIMENSION_SET) != MEASURED_DIMENSION_SET) {throw new IllegalStateException("onMeasure() did not set the"+ " measured dimension by calling"+ " setMeasuredDimension()");}mPrivateFlags |= LAYOUT_REQUIRED;}mOldWidthMeasureSpec = widthMeasureSpec;mOldHeightMeasureSpec = heightMeasureSpec;}

View.java 的onMeasure

 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));}

ViewGroup.java measureChildWithMargins

/**
*  其 中 参 数parentHeightMeasureSpec是该child的父视图传递过来的measureSpec,参 数 heightUsed* 是在该measureSpec中,父视图已经使用了的高度。*/protected void measureChildWithMargins(View child,int parentWidthMeasureSpec, int widthUsed,int parentHeightMeasureSpec, int heightUsed) {/*** 1) 调 用 child.getLayoutParmas()获得子视图的LayoutParams属性。该步虽然看起来只有一行代码,* 但其中却蕴涵了一组函数调用。首先来看该函数的返回值,在 View类 中 ,该函数的默认返回值是* ViewGroup.LayoutParams,而此处却被强制类型转换为ViewGroup.MarginLayoutParams类型。从程序的* 角度来讲,大家都知道,强制类型转换一般只能把子类强制转换为父类,而不能把父类强制转换为子类,* 除非该对象本身就是子类对象,否则会发生转换错误。而 此 处 MarginLayoutParams是子类,其父类是* LayoutParams,但代码中却把getLayoutParams()返回值强制转换为了 一个子类MarginLayoutParams对象,* 这是为什么呢?*这就要来看View对 象 的LayoutParams属性是如何被赋值的。创建一个View对象一般有两种方法,* 一种是使用XML文件静态描述,另一种是程序动态调用View类的构造函数,构造函数中指明所使用* LayoutParams参数。两种方法的本质是相同的,因此这里仅介绍第一种方法。**/final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();/*** 2 调用两次getChildMeasureSpec()函数,分别计算出该子视图的宽度和高度的Spec。前面曾经说* 过,子视图所占布局的大小取决于两个方面,一个是父视图提供的规格,另一个是子视图本身希望占用* 的大小,而这就是该函数参数的意义。*/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()函数。子视图可以重载onMeasure()函数,并可调用setMeasureDimension()函数设置任意* 大小的布局,而这将成为该子视图的最终布局大小*/child.measure(childWidthMeasureSpec, childHeightMeasureSpec);}

参 数 spec正是父视图提供的spec,源码中对应的变量是parentHeightMeasureSpec,这个值是int型 。
高 16位 代 表specMode, —共有三种模式,分别是AT—MOST、 EXACTLY及 UNSPECIFIED;低 16位
代 表 specSize,对于 非UNSPECIFIED模式,该值指父视图所允许的最大尺寸或者期望的理想尺寸。
参 数padding代表的是在父视图提供的spec尺寸中,已经使用的多少,源码中该值包含了 padding
填充、 margin空余,以及父视图所提供的已经使用的高度heightUsed:

m P a d d i n g T o p + m P a d d i n g B o t t o m + l p .t o p M a r g i n + l p .b o t t o m M a r g i n
+ h e i g h t U s e d

getChildMeasureSpec()中会从parent的 specSize中减去该padding,以便子视图使用已用的空间。
参 数 childDimension即为子视图期望获得的高度,其值来源于lp.height,这个值正是XM L文件中
andorid:layout_height对 应 的 值 , 可 能 是 一 个 具 体 的 值 , 也 可 能 是 MATCH_PARENT或者
WRAP_CONTENTo
getChildMeasnreSpecO的作用就是根据以上两个条件确定子视图的“测量规格”,注意,为什么这里
确定的不是最终子视图的尺寸而只是“测量规格” ?读者可以换一个角度来理解parentMeasureSpec和
lp.height这两个参数,前者实际上是指父视图可以提供的尺寸,而对一个应用程序而言,程序员必须负
责父视图所包含的所有子视图的排列关系,以达到一个优美的界面布局,因此,程序员才使用lp.height
指定期望该子视图的大小,而至于子视图到底有多大,还需要征询子视图本身的意思,所以该函数并不
能最终确定视图的尺寸。

 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 = 0;resultMode = MeasureSpec.UNSPECIFIED;} else if (childDimension == LayoutParams.WRAP_CONTENT) {// Child wants to determine its own size.... find out how// big it should beresultSize = 0;resultMode = MeasureSpec.UNSPECIFIED;}break;}return MeasureSpec.makeMeasureSpec(resultSize, resultMode);}```

measure()源码分析相关推荐

  1. android字符显示流程图,Android应用层View绘制流程与源码分析

    1  背景 还记得前面<Android应用setContentView与LayoutInflater加载解析机制源码分析>这篇文章吗?我们有分析到Activity中界面加载显示的基本流程原 ...

  2. Spark源码分析之七:Task运行(一)

    在Task调度相关的两篇文章<Spark源码分析之五:Task调度(一)>与<Spark源码分析之六:Task调度(二)>中,我们大致了解了Task调度相关的主要逻辑,并且在T ...

  3. android view 源码分析,Android ViewPager源码详细分析

    1.问题 由于Android Framework源码很庞大,所以读源码必须带着问题来读!没有问题,创造问题再来读!否则很容易迷失在无数的方法与属性之中,最后无功而返. 那么,关于ViewPager有什 ...

  4. Hbase源码分析:Hbase UI中Requests Per Second的具体含义

    Hbase源码分析:Hbase UI中Requests Per Second的具体含义 让运维加监控,被问到Requests Per Second(见下图)的具体含义是什么?我一时竟回答不上来,虽然大 ...

  5. 39、自定义控件(四)-- View源码分析

    一.View源码分析 ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的三大流程全是通过ViewRoot来完成的. 在Activ ...

  6. 安卓PopupWindow使用详解与源码分析(附项目实例)

    基本用法 首先定义弹窗的Layout文件 res/layout/popup_window.xml <?xml version="1.0" encoding="utf ...

  7. java地图源码_Java集合源码分析(四)HashMap

    一.HashMap简介 1.1.HashMap概述 HashMap是基于哈希表的Map接口实现的,它存储的是内容是键值对映射.此类不保证映射的顺序,假定哈希函数将元素适当的分布在各桶之间,可为基本操作 ...

  8. 8CollapsingToolbarLayout源码分析

    8CollapsingToolbarLayout源码分析 本文针对上篇文章进行源码分析 纯色Toolbar滑动 最简单代码 先从最简单的看起 <!--这里必须要写fitsSystemWindow ...

  9. TCP拥塞控制算法BBR源码分析

      BBR是谷歌与2016年提出的TCP拥塞控制算法,在Linux4.9的patch中正式加入.该算法一出,瞬间引起了极大的轰动.在CSDN上也有众多大佬对此进行分析讨论,褒贬不一.   本文首先对源 ...

最新文章

  1. 【有奖辩论】工程师和销售创业谁更有优势?
  2. 饿了么四年、阿里两年:研发路上的一些总结与思考
  3. PyQt5 技术篇-调用颜色对话框(QColorDialog)获取颜色,调色板的调用。
  4. cmd安装linux服务器,cmdbuild安装
  5. mybatis实现CRUD(不使用DAO)
  6. 使用curl工具测试SAP Spartacus的SSR模式是否工作正常
  7. 从阿里中台战略看企业IT架构转型之道(下)
  8. 产品经理需要向上思考
  9. P1614 爱与愁的心痛(python3实现)
  10. Java快速入门学习笔记2 | Java语言中的基本类型
  11. Nginx 的配置文件介绍
  12. JAVA敏捷开发环境搭建
  13. 【渝粤教育】21秋期末考试网络金融10248k2
  14. 精灵五笔 优化指南【原】
  15. 微软模拟飞行10厦门航空涂装_《微软飞行模拟》或很快迎来技术公测
  16. 如何一键下载或保存微博里面的短视频?
  17. HDU 1069 DP
  18. DateTrack功能介绍-如何删除终止日期?
  19. Buffer的基本用法
  20. 网速是什么意思?带宽是什么意思?1M网速的下载速度应是多少?[转.baidu]

热门文章

  1. Deepin v20 手动安装大黄蜂驱动(清华同方T45PRO-GAR-21053)
  2. 贝叶斯分类器的MapReduce实现(VMware + Hadoop)
  3. 6大B2C购物系统比较
  4. Kendo UI 绑定行点击事件
  5. 工作站和塔式服务器有什么区别
  6. Spring——七大核心模块
  7. [Algorithmic Toolbox学习笔记][week6]0/1 Knapsack Problem
  8. 为什么android studio的tools中没有android选项
  9. Web应用程序停止时无法注销它。 为防止内存泄漏,JDBC驱动程序已被强制取消注册。
  10. CNN基础论文 精读+复现---- ResNet(二)