【转载】快速理解android View的测量onMeasure()与MeasureSpec

笔者之前有一篇文章已经使用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():

[java] view plain copy

  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+左键点进去看一下,代码如下:

[java] view plain copy

  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()中如下代码:

[java] view plain copy

  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

原文地址:https://www.cnblogs.com/Blue-Keroro/p/9070054.html

时间: 2024-10-17 08:58:52

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

快速理解android View的测量onMeasure()与MeasureSpec

笔者之前有一篇文章已经使用onMeasure()解决了listview与scollview的显示冲突问题,博客地址如下: onMeasure简单方法 完美解决ListView与ScollView冲突问题! 在此就针对View的测量以及onMeasure()涉及的几个问题做一个详细解释: 一.MeasureSpec的概念: MeasureSpec通过将SpecMode和SpecSize打包成一个int值来避免过多的对象内存分配,为了方便操作,其提供了打包和解包的方法.SpecMode和SpecSi

深入理解Android View(转)

做android其实也有一段时间了,我们每个人都会碰到一些这样或那样的问题,碰到问题了就拼命百度,可是发现,我们解决问题的能力并没有提升很多,所以我才有想总结一下我项目中所用过的相关知识,并了解一下Android源代码中是如何定义这些属性的,如何去实现的.以后再碰到类似的问题,我该如何实现.本人也不常写博客,希望各位博友能指点,分享,并提出博客中不正确的地方,共勉!    首先我发一份我做的关于Android View深入实现的的XMind的思维导图,可以帮助我一起整理思路,若是博友有什么想到的

深入理解Android View(1)

做android其实也有一段时间了,我们每个人都会碰到一些这样或那样的问题,碰到问题了就拼命百度,可是发现,我们解决问题的能力并没有提升很多,所以我才有想总结一下我项目中所用过的相关知识,并了解一下Android源代码中是如何定义这些属性的,如何去实现的.以后再碰到类似的问题,我该如何实现.本人也不常写博客,希望各位博友能指点,分享,并提出博客中不正确的地方,共勉! 首先我发一份我做的关于Android View深入实现的的XMind的思维导图,可以帮助我一起整理思路,若是博友有什么想到的地方可

Android view的测量及绘制

讲真,自我感觉,我的水平真的是渣的一匹,好多东西都只停留在知道和会用的阶段,也想去研究原理和底层的实现,可是一看到代码就懵逼了,然后就看不下去了, 说自己不着急都是骗人的,我自己都不信,前两天买了本<Android 群英传>,江湖上都说这是一本初级过渡到中级不错的进阶书,所以准备看一下,才看了两天,今天 看到了view的测量及绘制,还有自定义view(还没看完),学到什么就写篇博客吧,算是对自己所学的一个总结和记录吧,也可以督促自己,如果有讲的不对的地方或者 有歧义的地方,欢迎大家吐槽批评我!

android View的测量和绘制

本篇内容来源于android 群英传(徐易生著) 我写到这里,是觉得徐易生讲的确实很好, 另外加入了一些自己的理解,便于自己基础的提高. 如果要绘制一个View , 就需要先取测量它,也就是需要知道它的大小和位置. 这样我们就能在屏幕中滑出来它了.这个过程是在onMeasure()方法中完成的. 一.测量模式 测量view的大小时,需要用到MeasureSpec (测量规范)这个类来指定测量模式 ,一共有3种 EXACTLY (精确模式) , 系统默认值. 如果我们指定控件宽高为 xxdp, x

深入理解android view 生命周期

作为自定义 view 的基础,如果不了解Android  view 的生命周期 , 那么你将会在后期的维护中发现这样那样的问题 ....... 做过一段时间android 开发的同学都知道,一般 onXXX 函数都是系统的回调函数.而这篇 blog 也是基于这个思想(或许有点笨)...... 首先来看三分  创建view 的 日志信息 (自定义View 配置到xml文件中): android:visibility=gone [html] view plain copy 03-25 19:56:5

Android View的测量

一.简介 Android系统在绘制View前,必须对View进行测量,即告诉系统该画一个多大的View.这个过程在onMeasure()方法中进行.Android系统提供了MeasureSpec类,通过帮助我们测量View. 测量模式可以分为三种: EXACTLY:即为精确值模式,系统默认使用的是EXACTLY模式. AT_MOST:即最大值模式,当控件的layout_width属性或layout_height属性指定为wrap_content时,控件大小一般随着控件的子空间或内容的变化而变化,

Android View 的测量流程详解

概述 上一篇 Android DecorView 与 Activity 绑定原理分析 分析了在调用 setContentView 之后,DecorView 是如何与 activity 关联在一起的,最后讲到了 ViewRootImpl 开始绘制的逻辑.本文接着上篇,继续往下讲,开始分析 view 的绘制流程. 上文说到了调用 performTraversals 进行绘制,由于 performTraversals 方法比较长,看一个简化版: // ViewRootImpl 类 private vo

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

本文转载自: http://blog.csdn.net/innost/article/details/50377905 一.背景 这个选题很大,但并不是一开始就有这么高大上的追求.最初之时,只是源于对Xposed的好奇.Xposed几乎是定制ROM的神器软件技术架构或者说方法了.它到底是怎么实现呢?我本意就是想搞明白Xposed的实现原理,但随着代码研究的深入,我发现如果不了解虚拟机的实现,而仅简单停留在Xposed的调用流程之上,那真是对Xposed最大的不敬了.另外,歪果仁为什么能写出Xpo