笔者之前有一篇文章已经使用onMeasure()解决了listview与scollview的显示冲突问题,博客地址如下:

onMeasure简单方法 完美解决ListView与ScollView冲突问题!

在此就针对View的测量以及onMeasure()涉及的几个问题做一个详细解释:

一、MeasureSpec的概念:

MeasureSpec通过将SpecMode和SpecSize打包成一个int值来避免过多的对象内存分配,为了方便操作,其提供了打包和解包的方法。SpecMode和SpecSize也是一个int值,一组SpecMode和SpecSize可以打包为一个MeasureSpec,而一个MeasureSpec可以通过解包的形式来得出其原始的SpecMode和SpecSize。

读者只要记住以下一句话即可:

MeasureSpec的值由specSize和specMode共同组成的,其中specSize记录的是大小,specMode记录的是规格。

二、SpecMode的三种模式:

1. EXACTLY

当我们将控件的“layout_width”属性或者“layout_height”属性指定为具体数值时,比如“android:layout_width="200dp"”,或者指定为“match_parent”时,系统会使用这个模式。

2. AT_MOST

当控件的“layout_width”属性或者“layout_height”属性设置为“wrap_content”时,控件大小一般会随着内容的大小而变化,但是无论多大,也不能超过父控件的尺寸。

3. UNSPECIFIED

表示开发人员可以将视图按照自己的意愿设置成任意的大小,没有任何限制。这种情况比较少见,一般在绘制自定义View的时候才会用到。

三、View的测量到底和什么有关呢?

要探其原理,首先要和大家说明一点,一个View只需要MeasureSpec确定,那么在onMeasure中就可以测量它的宽高,所以我们可以将问题直接转化成“一个View的MeasureSpec是如何确定的呢?”

普通的View的measure过程由VIewGroup传递而来,此处我们根据源码来做一个解释,先看一下ViewGroup中的measureChildWithMargins():

  1. protected void measureChildWithMargins(View child,
  2. int parentWidthMeasureSpec, int widthUsed,
  3. int parentHeightMeasureSpec, int heightUsed) {
  4. final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
  5. final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
  6. mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
  7. + widthUsed, lp.width);
  8. final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
  9. mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
  10. + heightUsed, lp.height);
  11. child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
  12. }

从中,我们可以看到一个view的宽高,都是通过getChildMeasureSpec()这个方法获得的,那么这里面又是怎么实现的呢?我们不妨Control+左键点进去看一下,代码如下:

  1. public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
  2. int specMode = MeasureSpec.getMode(spec);
  3. int specSize = MeasureSpec.getSize(spec);
  4. int size = Math.max(0, specSize - padding);
  5. int resultSize = 0;
  6. int resultMode = 0;
  7. switch (specMode) {
  8. // Parent has imposed an exact size on us
  9. case MeasureSpec.EXACTLY:
  10. if (childDimension >= 0) {
  11. resultSize = childDimension;
  12. resultMode = MeasureSpec.EXACTLY;
  13. } else if (childDimension == LayoutParams.MATCH_PARENT) {
  14. // Child wants to be our size. So be it.
  15. resultSize = size;
  16. resultMode = MeasureSpec.EXACTLY;
  17. } else if (childDimension == LayoutParams.WRAP_CONTENT) {
  18. // Child wants to determine its own size. It can't be
  19. // bigger than us.
  20. resultSize = size;
  21. resultMode = MeasureSpec.AT_MOST;
  22. }
  23. break;
  24. // Parent has imposed a maximum size on us
  25. case MeasureSpec.AT_MOST:
  26. if (childDimension >= 0) {
  27. // Child wants a specific size... so be it
  28. resultSize = childDimension;
  29. resultMode = MeasureSpec.EXACTLY;
  30. } else if (childDimension == LayoutParams.MATCH_PARENT) {
  31. // Child wants to be our size, but our size is not fixed.
  32. // Constrain child to not be bigger than us.
  33. resultSize = size;
  34. resultMode = MeasureSpec.AT_MOST;
  35. } else if (childDimension == LayoutParams.WRAP_CONTENT) {
  36. // Child wants to determine its own size. It can't be
  37. // bigger than us.
  38. resultSize = size;
  39. resultMode = MeasureSpec.AT_MOST;
  40. }
  41. break;
  42. // Parent asked to see how big we want to be
  43. case MeasureSpec.UNSPECIFIED:
  44. if (childDimension >= 0) {
  45. // Child wants a specific size... let him have it
  46. resultSize = childDimension;
  47. resultMode = MeasureSpec.EXACTLY;
  48. } else if (childDimension == LayoutParams.MATCH_PARENT) {
  49. // Child wants to be our size... find out how big it should
  50. // be
  51. resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
  52. resultMode = MeasureSpec.UNSPECIFIED;
  53. } else if (childDimension == LayoutParams.WRAP_CONTENT) {
  54. // Child wants to determine its own size.... find out how
  55. // big it should be
  56. resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
  57. resultMode = MeasureSpec.UNSPECIFIED;
  58. }
  59. break;
  60. }
  61. return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
  62. }

代码比较长,读者可以比较焦急——不用害怕,我们不需要完全理解它的原理,我们只需要知道View的测量是如何实现的就行了。

看到源码方法中的三个参数,并且比较measureChildWithMargins()方法中传递给getChildMeasureSpec()三个值,我们很快就可以理解,一个View的测量过程是由父布局的MeasureSpec和该View的LayoutParams决定的。

读者可以看measureChildWithMargins()中如下代码:

  1. final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
  2. mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
  3. + widthUsed, lp.width);

要测量子部局的宽度的MeasureSpec,需要传入3个参数:

第一个参数:父布局的宽度的MeasureSpec

第二个参数:子部局的padding值,子部局的LayoutParams的Margin值

第三个参数:子部局的LayoutParams的宽度

如果对View的测量过程由更深入的求知欲的,推荐读者可以自己看一下源码。

版权声明:本文为博主许佳佳原创文章,转载请务必注明出处。 https://blog.csdn.net/Double2hao/article/details/51553703

【转载】快速理解android View的测量onMeasure()与MeasureSpec的更多相关文章

  1. Android view的测量及绘制

    讲真,自我感觉,我的水平真的是渣的一匹,好多东西都只停留在知道和会用的阶段,也想去研究原理和底层的实现,可是一看到代码就懵逼了,然后就看不下去了, 说自己不着急都是骗人的,我自己都不信,前两天买了本& ...

  2. Android View 如何测量

    对于Android View的测量,我们一句话总结为:"给我位置和大小,我就知道您长到那里". 为了让大家更好的理解这个结论,我这里先讲一个日常生活中的小故事:不知道大家玩过&qu ...

  3. 深入理解Android View(转)

    做android其实也有一段时间了,我们每个人都会碰到一些这样或那样的问题,碰到问题了就拼命百度,可是发现,我们解决问题的能力并没有提升很多,所以我才有想总结一下我项目中所用过的相关知识,并了解一下A ...

  4. android View的测量和绘制

    本篇内容来源于android 群英传(徐易生著) 我写到这里,是觉得徐易生讲的确实很好, 另外加入了一些自己的理解,便于自己基础的提高. 另外参考:http://www.gcssloop.com/cu ...

  5. 深入理解android view 生命周期

    作为自定义 view 的基础,如果不了解Android  view 的生命周期 , 那么你将会在后期的维护中发现这样那样的问题 ....... 做过一段时间android 开发的同学都知道,一般 on ...

  6. [转载] 深入理解Android之Java虚拟机Dalvik

    本文转载自: http://blog.csdn.net/innost/article/details/50377905 一.背景 这个选题很大,但并不是一开始就有这么高大上的追求.最初之时,只是源于对 ...

  7. View在测量时的MeasureSpec由什么决定?

    我们都知道系统要确定View的大小,首先得先获得MeasureSpec,再通过MeasureSpec来决定View的大小. MeasureSpec(32为int值)由两部分组成: SpecMode(高 ...

  8. [转载+实践理解]Android动画---如何正确使用平移动画(关于fillBefore和fillAfter的一点说明)(转载)

    红色部分为自己的实践理解 如何实现将View向上平移自身高度一半的距离? TranslateAnimation translate = new TranslateAnimation( Animatio ...

  9. [转载] 快速理解Kafka分布式消息队列框架

    转载自http://blog.csdn.net/xiaolang85/article/details/18048631 ==是什么 == 简单的说,Kafka是由Linkedin开发的一个分布式的消息 ...

随机推荐

  1. Codeforces Round #295 (Div. 2) B. Two Buttons (DP)

    题意:有两个正整数\(n\)和\(m\),每次操作可以使\(n*=2\)或者\(n-=1\),问最少操作多少次使得\(n=m\). 题解:首先,若\(n\ge m\),直接输出\(n-m\),若\(2 ...

  2. Pdf和Office相关归集

    Spire 支持Pdf.Office等的诸多操作,使用方便,需收费,免费版本仅支持10页以内的操作,在 这里 可以下载库. 优点 测试过打印效果佳,操作简便. 缺点 PDF打印慢,免费版本仅支持10页 ...

  3. 018-019 NET5_内置容器支持依赖注入+IServiceCollection的生命周期

    概念: DI依赖注入: IServiceCollection仅支持构造函数注入 什么是依赖注入? 如果对象A依赖对象B,对象B依赖对象C,就可以先构造对象C,然后传递给对象B,再把对象B传递给A.得到 ...

  4. 你不知道的 JS (系列丛书) - 第二版

    你不知道的 JS (系列丛书) - 第二版 You Don't Know JS (book series) - 2nd Edition https://github.com/learning-js-b ...

  5. CSS pseudo classes All In One

    CSS pseudo classes All In One CSS 伪类 https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes ...

  6. CSS3 Animation & Weather Icons

    CSS3 Animation & Weather Icons google fonts <link href='https://fonts.googleapis.com/css?fami ...

  7. how to stop MongoDB from the command line

    how to stop MongoDB from the command line stop mongod https://docs.mongodb.com/manual/tutorial/manag ...

  8. how to measure function performance in javascript

    how to measure function performance in javascript Performance API Performance Timeline API Navigatio ...

  9. CSS BEM

    CSS BEM Block, Element, Modifier https://en.bem.info/methodology/quick-start/ BEM /* Block component ...

  10. 比特币跌破3.5万美元,巨鲸们将目光瞄向SPC算力币

    比特币最近又迎来了大幅下跌,截至周三(1月20日),比特币跌幅超过5%,跌破3.5万美元.很显然,比特币没有预期那样顺顺利利地登顶4万美元,反而又出现了回调迹象.有些巨鲸们在大肆囤币,然而也有些巨鲸们 ...