最近有人问了我关于measure 和 onMeasure的一些问题,什么时候调用measure方法, 两者的区别,什么时候重写onMeasure方法。其实网上有很多人写过这方面的博客。我觉得不要因为网上有了,就不写。看懂是一回事,讲出来是一回事,写出来又是另外一回事。看了东西还是别人了,只有通过写或是讲出来才能更深刻的理解。

我们先看下什么时候会调用 measure方法:

讲到view的绘制原理上,肯定都会提到ViewRootImpl类,该类是activity 的view 树与Window的中间通信者。它里面的mView对象指向的是DecorView。ViewRootImpl类是View绘制过程(测量,布局,绘制)的起点。那么measure方法是怎么进行的呢?

我们先看下调用顺序:

通过上面的调用顺序,我们可以看到measure是在什么时候调用,在View里,有个mParent的变量。这个变量其实就是ViewRootImpl. 所以在调用View的requestFitSystemWindows, requestLayout, invalidateChildInParent时候,都会调用measure方法。

那measure方法到底是干什么用的。其实它主要是用于计算并获取该View的实际大小,也就是mMeasuredWidth和mMeasuredHeight两个值。

1.首先判断是否有设置为opticalBounds的属性,如果当前的opticalBounds的属性和父类的不一致,就重新计算wdithMeasureSpec和heightMeasureSpec。

 boolean optical = isLayoutModeOptical(this);
if (optical != isLayoutModeOptical(mParent)) {
Insets insets = getOpticalInsets();
int oWidth = insets.left + insets.right;
int oHeight = insets.top + insets.bottom;
widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth);
heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight);
}

2. 如果有窗口移动或是reSize的操作,导致的强制刷新,或是view的宽度或是长度有变化时候。如果是不用measure cache,那么需要调用onMeasure方法进行进行view的width和height。如果有measure cache,那么只需要拿到measure cache里的值进行更新就可以了。

 if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||
widthMeasureSpec != mOldWidthMeasureSpec ||
heightMeasureSpec != mOldHeightMeasureSpec) { // first clears the measured dimension flag
mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; resolveRtlPropertiesIfNeeded(); int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :
mMeasureCache.indexOfKey(key);
if (cacheIndex < 0 || sIgnoreMeasureCache) {
// measure ourselves, this should set the measured dimension flag back
onMeasure(widthMeasureSpec, heightMeasureSpec);
mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
} else {
long value = mMeasureCache.valueAt(cacheIndex);
// Casting a long to int drops the high 32 bits, no mask needed
setMeasuredDimensionRaw((int) (value >> 32), (int) value);
mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
} // flag not set, setMeasuredDimension() was not invoked, we raise
// an exception to warn the developer
if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) {
throw new IllegalStateException("View with id " + getId() + ": "
+ getClass().getName() + "#onMeasure() did not set the"
+ " measured dimension by calling"
+ " setMeasuredDimension()");
} mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;
}

3.最后保存当前的值到measure cache里和重新记录old值,key值是用 widthMeasureSpec和heightMeasureSpec拼凑的64位数

 // Suppress sign extension for the low bytes
long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;
if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); // ......省略....
mOldWidthMeasureSpec = widthMeasureSpec;
mOldHeightMeasureSpec = heightMeasureSpec; mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |
(long) mMeasuredHeight & 0xffffffffL); // suppress sign extension

View里的onMeasure 做得事情很简单,就是根据spec来计算具体的值。当然了如果是RelativeLayout等ViewGroup里的onMeasure就会相当复杂。

那在上面时候需要重写onMeasure方法呢?

一般是需要自己去定义高宽规则的时候,比如需要显示一个特定高度的listView。不管规则怎么变,在重新计算高宽后,一定要调用setMeasuredDimension

View 的measure 和onMeasure的更多相关文章

  1. Android中View的绘制过程 onMeasure方法简述 附有自定义View例子

    Android中View的绘制过程 onMeasure方法简述 附有自定义View例子 Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android fr ...

  2. 普通View的measure流程

    对于普通的view,其测量在ViewGroup中的measureChildWithMargins函数中调用child view的measure开始测量. 1:从measure函数开始 public f ...

  3. 源码解析Android中View的measure量算过程

    Android中的Veiw从内存中到呈现在UI界面上需要依次经历三个阶段:量算 -> 布局 -> 绘图,关于View的量算.布局.绘图的总体机制可参见博文< Android中View ...

  4. Android View体系(七)从源码解析View的measure流程

    前言 在上一篇我们了解了Activity的构成后,开始了解一下View的工作流程,就是measure.layout和draw.measure用来测量View的宽高,layout用来确定View的位置, ...

  5. View的measure机制

    Android中View框架的工作机制中,主要有三个过程: 1.View树的测量(measure)Android View框架的measure机制     2.View树的布局(layout) And ...

  6. Android自己定义view之measure、layout、draw三大流程

    自己定义view之measure.layout.draw三大流程 一个view要显示出来.须要经过測量.布局和绘制这三个过程,本章就这三个流程具体探讨一下.View的三大流程具体分析起来比較复杂,本文 ...

  7. 【Android - 自定义View】之View的measure过程解析

    measure(测量)过程是View的工作流程中最开始.最核心的过程,在这个过程中负责确定View的测量宽/高. 对于View和ViewGroup,measure过程有不同的执行方法:如果目标是一个原 ...

  8. 什么?这么精髓的View的Measure流程源码全解析,你确定不看看?

    前言 Android开发中我们平时接触最多的是各种View, View是一个比较大的体系,包含了绘制流程.事件分发.各种动画.自定义View 等等.前几天我写了一篇事件分发源码解析的文章, 今天我们来 ...

  9. 【转】Android中View的绘制过程 onMeasure方法简述 附有自定义View例子

    Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android framework将会处理绘制过程,Activity只需提供它的布局的根节点. 绘制过程从布 ...

随机推荐

  1. 最简单的Linux虚拟机磁盘扩容方法

    思路:1.虚拟机增加磁盘容量: 2.将增加的磁盘容量增加到系统分区中: 准备阶段: 下载Gparted软件:https://sourceforge.net/projects/gparted/files ...

  2. CodeForces 429B

    Working out Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u   Desc ...

  3. Redis系列二(yum切换为网易163)

    这个可能和Redis没有直接的关系... 是我在yum install的时候发现centos的yum实在是太慢,上网查了下.网易163有个yum镜像,为了让CentOS6使用速度更快的YUM更新源,可 ...

  4. [html5] 学习笔记-SVG

    1.SVG介绍:什么是SVG? 1)SVG指可伸缩矢量图形(Scalable Vector Graphics) 2)SVG用来定义用于网络的基于矢量的图形 3)SVG使用XML格式定义图形 4)SVG ...

  5. Wireshark网络抓包(四)——工具

    一.基本信息统计工具 1)捕获文件属性(Summary) 1. File:了解抓包文件的各种属性,例如抓包文件的名称.路径.文件所含数据包的规模等信息 2. Time:获悉抓包的开始.结束和持续时间 ...

  6. Program terminated with signal SIGKILL,Killed

    车载后视镜机器,Liinux + qtUI形式,前后双路,前一天晚上开机用gdb run DvrUI,第二天早上回来一看,机器绿屏卡死了,录像预览停止刷新了,sd录像也停止了.点击无任何反应. 看gd ...

  7. Struts2 struts.xml配置

    <?xml version="1.0" encoding="GBK"?> <!--指定 Struts2 的DTD信息 DTD 指 Docume ...

  8. php安装详解

    获取资源: cd /usr/local/src/ wget http://cn2.php.net/distributions/php-5.4.45.tar.bz2 tar jxvf php-5.4.4 ...

  9. Oracle instant client在windows下的安装和使用

    安装 * 从oracle官方网站下载instant client文件,一般来说,有basic.sqlplus.odbc.jdbc,就足够用的了: instantclient-basic-win32-1 ...

  10. (Jquery)避免数据相加小数点后产生多位数和计算精度损失

    /** * 加法运算,避免数据相加小数点后产生多位数和计算精度损失. * * @param num1加数1 | num2加数2 */ function numAdd(num1, num2) { var ...