• MeasureSpec.getSize(int measureSpec)

MeasureSpec 其中前 2 位表示测量的模式 SpecMode,后边 30 位表示某种测量模式下的尺寸 SpecSize。

MeasureSpec 中有三种测量模式

  • UNSPECIFIED 不指定具体尺寸,完全由 View 自己发挥。
  • EXACTLY 精确模式,这种模式下使用后边的 specSize ,一般对应于 LayoutParams 的 match_content 和设置的精确尺寸。
  • AT_MOST 最大模式,这种模式下 view 的最大尺寸不能超过后边的 specSize ,一般对应于 LayoutParams 的 wrap_content

在测量 View 的时候,系统会将自己的 LayoutParams 参数在父容器的 MeasureSpec 影响下转换为自己的MeasureSpec ,然后再通过这个 MeasureSpec 测量自身的宽高。

需要注意的是View 的MeasureSpec 不是唯一由 LayoutParams 决定的,是在父容器的共同影响下创建来的。

在 ViewGroup 的 measureChild() 可以看到具体的实现思路,getChildMeasureSpec() 里就是将 layoutParams 转换为 measureSpec 的实现思路。

protected void measureChild(View child, int parentWidthMeasureSpec,
int parentHeightMeasureSpec) {
//拿到子元素的 LayoutParams 参数
final LayoutParams lp = child.getLayoutParams();

//创建子元素的 measureSpec
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
mPaddingLeft + mPaddingRight, lp.width);
final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
mPaddingTop + mPaddingBottom, lp.height);

//将测量传递到子元素
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}

public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
//解析父容器的 measureSpec ,解析出模式和尺寸
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) {
// 父容器是精确模式的情况,设置了精确尺寸。
case MeasureSpec.EXACTLY:
if (childDimension >= 0) {
//子元素本身是设置的精确尺寸,就是EXACTLY 模式,尺寸就是设置的尺寸。
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// 子元素设置的 match_content 充满入容器,就把尺寸设置为入容器的尺寸,模式设置为EXACTLY
resultSize = size;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// 包裹模式下,子元素可以自己设置尺寸,但是不能超过夫容器的尺寸。模式为AT_MOST,尺寸为父容器的尺寸。
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
}
break;

//父容器是最大模式
case MeasureSpec.AT_MOST:
if (childDimension >= 0) {
// 设置为子元素的尺寸,为精确模式
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// 子元素想充满父容器,应该设置为父容器的尺寸,但是父容器是最大模式,没有精确尺寸。
// 所以将子元素设置为最大模式,不能超过父容器目前的尺寸。
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// 子元素没有精确尺寸,想包裹自身,这种模式下,设置为最大模式,不超过父容器尺寸就好。
// bigger than us.
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
}
break;

// 父容器没有限制,子元素自己发挥
case MeasureSpec.UNSPECIFIED:
if (childDimension >= 0) {
//子元素自己有设置的值,就好实用自己的值,设置为精确模式
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// 子元素想充满父容器,那就找到父容器的尺寸,但父容器的尺寸未知,还是要自己发挥 UNSPECIFIED。
resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
resultMode = MeasureSpec.UNSPECIFIED;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// 只元素是包裹自身,父容器无法给出参考,所以让子元素自己去随意发挥,仍然是UNSPECIFIED
resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
resultMode = MeasureSpec.UNSPECIFIED;
}
break;
}
//使用打包方法,将子元素的模式和尺寸打包并返回
return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}

measure 流程是在 ViewRoot 的 performMeasure() 里开始的。

在这里会将 DecorView 的 layoutParams 在 window 的 measureSpec 影响下转换为自己的 measureSpec 。 然后调用 DecorView 的 measure() 将宽高的 measureSpec 传入,在 measure() 里,decorView 开始自己的测量。

从 DecorView 的 measure() 开始,整个 View 树的测量流程就开始了。

View 的测量都是在 measure() 里进行的,这是个 final 类型的方法,里面的实现比较简单会有一些判断调整,是否需要测量,会继续调用 onMeasure() 将 measureSpec 传进来,测量尺寸的确定最终是在 onMeasure() 里完成的。

通常我们自定义 View 都要重写这个方法实现自己的测量逻辑,包括我们常用的控件都是自己重写了这个方法实现自己的测量逻辑。

如果不重写 onMeasure(),会导致自定义 view 的 wrap_content 参数无效,具体可以看一下 getDefaultSize() 实现。

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

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 Mea

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》浏览器打开:qq.cn.hn/FTe 免费领取

sureSpec.EXACTLY:
//默认 精确模式和最大模式下都是使用后边的 specSize ,这会导致我们设置的 wrap_content 无效,始终是充满父容器。
result = specSize;
break;
}
return result;
}

protected int getSuggestedMinimumHeight() {
return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());

}

protected int getSuggestedMinimumWidth() {
return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}

View 和 ViewGroup 的测量过程是不同的。

单纯的 View 只需要在 onMeasure() 里完成自己的测量就可以了,ViewGroup 除了完成自己的测量外,还有子元素的测量。

ViewGroup 的 onMeasure() 是没有任何实现的,因为各个布局的特性不同,具体测量逻辑也是不同的,具体实现都在各个布局里。

但是 ViewGroup 里提供了 measureChildren() 方法,思路就是,遍历所有需要显示的子元素,取出他们的 LayoutParams 参数在自己 measureSpec 的影响下创建出子元素的 measureSpec ,然后将调用子元素的 measure() 将measureSpec 传递进去。

这里就将测量传递到了子元素。如果子元素是单纯的 View 控件只需要完成自己就可以了,如果是 ViewGroup 会继续将测量递归下去,直至完成整个 View 树的测量。

protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
final int size = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < size; ++i) {
final View child = children[i];
if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
//测量子元素,measureChild 见上面 MeasureSpec 里的代码。
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}

Android View 绘制流程,大厂直通车相关推荐

  1. android 绘图流程,Android View绘制流程

    前言 不知道大家有没有想过一个问题,当启动一个Activity的时候,相应的XML布局文件中的View是如何显示到屏幕上的?有些同学会说是通过onMeasure().onLayout().onDraw ...

  2. Android View 绘制流程

    前面讲到 Android View 加载流程,使用 LayoutInflater 将 xml 文件转变成 View ,但是还需要将 View 绘制出来,才能被用户看到,这一过程为绘制流程.由于 And ...

  3. Android View 测量流程(Measure)完全解析

    前言 上一篇文章,笔者主要讲述了DecorView以及ViewRootImpl相关的作用,这里回顾一下上一章所说的内容:DecorView是视图的顶级View,我们添加的布局文件是它的一个子布局,而V ...

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

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

  5. Android 系统(230)---View 绘制流程 —— 基础(1)

    View 绘制流程 -- 基础(1) View 绘制流程 -- 基础 1. View分类 类别 解释 特点 单一视图 即一个View,如 TextView 不包含子View 视图组 即多个View组成 ...

  6. 【朝花夕拾】Android自定义View篇之(一)View绘制流程

    前言 转载请申明转自[https://www.cnblogs.com/andy-songwei/p/10955062.html]谢谢! 自定义View.多线程.网络,被认为是Android开发者必须牢 ...

  7. 【朝花夕拾】Android自定义View之(一)手把手教你看懂View绘制流程——向源码要答案

    前言 原文:Android自定义View之(一)手把手教你看懂View绘制流程--向源码要答案 View作为整个app的颜值担当,在Android体系中占有重要的地位.深入理解Android View ...

  8. Android自定义View绘制流程

    Android视图层次结构简介 在介绍View绘制流程之前,咱们先简单介绍一下Android视图层次结构以及DecorView,因为View的绘制流程的入口和DecorView有着密切的联系. 我们平 ...

  9. Android应用层View绘制流程与源码分析

    前言 Activity中界面加载显示的基本流程原理,最终分析结果就是下面的关系: 看见没有,如上图中id为content的内容就是整个View树的结构,所以对每个具体View对象的操作,其实就是个递归 ...

最新文章

  1. R语言axis函数自定义可视化的坐标轴刻度线(axis ticks)
  2. Paddle内置的网络模型
  3. Python报错TypeError: 'str' object is not callable
  4. android 从底部网上的平移动画_Android属性动画,看完这篇够用了吧
  5. 如何在dva的effects中实现回调
  6. 3DSlicer14:Loadable Module
  7. Effective Java之请不要在新代码中使用原生态类型(二十三)
  8. LeetCode 1103. 分糖果 II
  9. Conda solving environment一晚上还不能完成有解吗?
  10. win32获取其它进程变量地址存放的信息
  11. 信息安全完全参考手册之风险分析(第二章)
  12. Python 爬虫-进阶开发之路
  13. 谷歌的下一个×××烦
  14. Windows下用VS2015+MSYS编译OpenH264
  15. cout一位小数_C++ cout 如何保留小数输出
  16. 跨时空的相遇~为她制作一个专属的QQ空间相册(附源代码)
  17. SCI论文写作高频词汇短语汇总
  18. 中国与美国光纤网络连接详解
  19. 前端的扁平化是什么意思
  20. 《天天数学》连载60:二月二十九日

热门文章

  1. 约瑟夫问题这是17世纪的法国数学家加斯帕在《数目的游戏问题》中讲的一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈
  2. Android Studio 4.0汉化教程
  3. 牛逼啊!一个随时随地写Python代码的神器
  4. 小白理财初级训练之经验总结
  5. 江苏高等学校计算机等级考试中心,江苏省高等学校计算机等级考试中心
  6. Unity3D之动画(Animation)的制作
  7. 行健客户管理软件 局域网络企业版 免费
  8. 计算机丢失physxloader.dll,physxloader.dll
  9. Hexo站点建设之——国际化(i18n)
  10. 王道操作系统___第三章01