前言

  View的绘制过程分为 measure、layout、draw三个步骤,接下来对这三个步骤逐一进行研究。

measure方法的签名

  1. public final void measure(int widthMeasureSpec, int heightMeasureSpec);

  measure方法用来测量View的尺寸。两个参数widthMeasureSpec/heightMeasureSpec声明了Parent View所能提供的宽/高。

  需要注意的是,widthMeasureSpec/heightMeasureSpec 这两个 int 型的参数是复合参数(compound parameters)。jvm中以32bit来存储int,最高两位表示“mode”,后面30位才是具体的数值。在View.java中有下面两个方法

  1. /**
  2. * Extracts the mode from the supplied measure specification.
  3. *
  4. * @param measureSpec the measure specification to extract the mode from
  5. * @return {@link android.view.View.MeasureSpec#UNSPECIFIED},
  6. * {@link android.view.View.MeasureSpec#AT_MOST} or
  7. * {@link android.view.View.MeasureSpec#EXACTLY}
  8. */
  9. public static int getMode(int measureSpec) {
  10. return (measureSpec & MODE_MASK);
  11. }
  12.  
  13. /**
  14. * Extracts the size from the supplied measure specification.
  15. *
  16. * @param measureSpec the measure specification to extract the size from
  17. * @return the size in pixels defined in the supplied measure specification
  18. */
  19. public static int getSize(int measureSpec) {
  20. return (measureSpec & ~MODE_MASK);
  21. }

  看到了吧,使用位操作&来获取最高两位的mode。2^2=4,这里只有用到了3种,它们分别的含义入下

  • UNSPECIFIED-ParentView对子View没有约束,后者可以是任意大小
  • AT_MOST-ParentView规定了尺寸上限,子View的大小不可以超过这个上限
  • EXACTLY-ParentView规定了子View的宽高,子View只能是这个宽高

  measure方法本身是声明为final的,CustomView必须实现自己的onMeasure方法,以便View.measure对此进行回调。在实现自己的CustomView.onMeasure之前,先来看看View中默认的onMeasure方法。

onMeasure

  在自定义View中,往往需要重写onMeasure方法,来设置View的measured width/height。要注意的一点是,计算完成后,必须调用setMeasuredDimension(int, int)来设置宽高,不然在上层measure方法会抛出IllegalStateException。自定View计算出的宽/高必须满足最小宽/高(通过getSuggestedMinimumWidth()、getSuggestedMinimumHeight()获取)。当然也可以在自定义View的onMeasure方法中直接调用View.onMeasure,如下

  1. @Override
  2. public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  4. }

  然而,View默认的onMeasure实现逻辑非常简单,恐怕不能满足自定义View的需求。

  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  2. setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
  3. getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
  4. }

  View.onMeasure简单粗暴地调用了setMeasuredDimension来设置measuredWidth/measuredHeight。其中使用的getDefaultSize(int, int)方法如下

  1. public static int getDefaultSize(int size, int measureSpec) {
  2. int result = size;
  3. int specMode = MeasureSpec.getMode(measureSpec);
  4. int specSize = MeasureSpec.getSize(measureSpec);
  5.  
  6. switch (specMode) {
  7. case MeasureSpec.UNSPECIFIED:
  8. result = size;
  9. break;
  10. case MeasureSpec.AT_MOST:
  11. case MeasureSpec.EXACTLY:
  12. result = specSize;
  13. break;
  14. }
  15. return result;
  16. }

  逻辑很简单,一个switch/case语句,根据SpecMode来判断返回。若为UNSPECIFIED,则返回minimumWidth;若为AT_MOST/EXACTLY,返回SpecWidth。

  到此为止,View的measure过程已经完成了。对于ViewGroup,可以猜想,它的onMeasure方法,是把所有子View的onMeasure做一次相加。我们来看一下具体是不是这样做的。

ViewGroup.measure

  ViewGroup继承了View类,理所应当地,我们试图在ViewGroup中查找是否重写了onMeasure方法——未果。不过我们惊喜地发现了measureChildren这个方法——用来遍历所有children,对每一个child进行measure

  1. protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
  2. final int size = mChildrenCount;
  3. final View[] children = mChildren;
  4. for (int i = 0; i < size; ++i) {
  5. final View child = children[i];
  6. if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
  7. measureChild(child, widthMeasureSpec, heightMeasureSpec);
  8. }
  9. }
  10. }

  measureChild中,将ViewGroup的padding加入了计算,最后调用child.measure,这里不予深究,也不再贴出代码。

  ViewGroup.java本身并没有重写onMeasure方法,在它的具体实现中,onMeasure根据具体情况,将children的measured size进行求和处理,具体可以参阅FrameLayout/LiearLayout/RelativeLayout 的代码。

小结

  对于measure过程的分析就到这里,下一篇我们继续探讨onLayout过程。

Android UI 绘制过程浅析(二)onMeasure过程的更多相关文章

  1. Android UI 绘制过程浅析(五)自定义View

    前言 这已经是Android UI 绘制过程浅析系列文章的第五篇了,不出意外的话也是最后一篇.再次声明一下,这一系列文章,是我在拜读了csdn大牛郭霖的博客文章<带你一步步深入了解View> ...

  2. 传感器仿真平台——UI绘制模块(二)

    这一章讲的是UI绘制模块 该模块的作用是将实验对象绘制出来,它可能是目标.传感器等等,由于事先并不知道会有哪些物体,也无法事先定义好某个对象该怎么画,以我懒人的性格,得了,就抛给用的人吧~喝前摇一摇, ...

  3. Android UI 绘制过程浅析(四)draw过程

    前言 draw是绘制View三个步骤中的最后一步.同measure.layout一样,通常不对draw本身进行重写,draw内部会调用onDraw方法,子类View需要重写onDraw(Canvas) ...

  4. Android UI 绘制过程浅析(三)layout过程

    前言 上一篇blog中,了解到measure过程对View进行了测量,得到measuredWidth/measuredHeight.对于ViewGroup,则计算出全部children的宽高进行求和. ...

  5. Android UI 绘制过程浅析(一)LayoutInflater简介

    前言 这篇blog是我在阅读过csdn大牛郭霖的<带你一步步深入了解View>一系列文章后,亲身实践并做出的小结.作为有志向的前端开发工程师,怎么可以不搞懂View绘制的基本原理——简直就 ...

  6. Android UI绘制流程及原理

    一.绘制流程源码路径 1.Activity加载ViewRootImpl ActivityThread.handleResumeActivity() --> WindowManagerImpl.a ...

  7. 简单研究Android View绘制一 测量过程

    2015-07-27 16:52:58 一.如何通过继承ViewGroup来实现自定义View?首先得搞清楚Android时如何绘制View的,参考Android官方文档:How Android Dr ...

  8. Android UI开发第四十一篇——墨迹天气3.0引导界面及动画实现

    周末升级了墨迹天气,看着引导界面做的不错,模仿一下,可能与原作者的代码实现不一样,但是实现的效果还是差不多的.先分享一篇以前的文章,android动画的基础知识,<Android UI开发第十二 ...

  9. 简单研究Android View绘制三 布局过程

    2015-07-28 17:29:19 这一篇主要看看布局过程 一.布局过程肯定要不可避免的涉及到layout()和onLayout()方法,这两个方法都是定义在View.java中,源码如下: /* ...

随机推荐

  1. 【matlab】MATLAB程序调试方法和过程

    3.8  MATLAB程序的调试和优化 在MATLAB的程序调试过程中,不仅要求程序能够满足设计者的设计需求,而且还要求程序调试能够优化程序的性能,这样使得程序调试有时比程序设计更为复杂.MATLAB ...

  2. Oracle GoldenGate for Big Data 12.2.0.1的新特性

    ogg for bigdata 12.2已经发布,新增有如下特性:支持java replicat进程OGG12.2中开发了基于java的replicat模式,以前的版本是基于extract进程中使用u ...

  3. 12-8下午 php语法

    <?php //var_dump(empty($a)); //判断变量是否为空//var_dump(isset($a)); //判断变量是否定义//$a = 10;//unset($a); // ...

  4. Neuroaesthetics神经美学

    欢迎您到脑科学的世界! 神经美学(或neuroaesthetics)是一个相对较新的经验主义美学的子学科.经验主义美学需要科学的方法来研究艺术和音乐的审美观念. neuroesthetics于2002 ...

  5. 问:Linux下Chrome标题栏中文乱码

    From:http://blog.csdn.net/loveaborn/article/details/29579787 在使用Linux的时候你会遇到一些奇奇怪怪的问题,不过,你会在解决这些问题的过 ...

  6. excel导入导出

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using FS.Exten ...

  7. Jqgrid 数据格式化配置

    默认格式化 $jgrid = { formatter : { integer : {thousandsSeparator: " ", defaultValue: '0'}, num ...

  8. SPOJ QTREE Query on a tree

    题意:给一颗n个点的树,有两种操作CHANGE i ti : 把第i条边的权变为tiQUERY a b : 问点a 到 点b 之间的边的最大权 思路:树剖处理边权.由于是边,所以只需要把边权处理到子节 ...

  9. (转)注意力机制(Attention Mechanism)在自然语言处理中的应用

    注意力机制(Attention Mechanism)在自然语言处理中的应用 本文转自:http://www.cnblogs.com/robert-dlut/p/5952032.html  近年来,深度 ...

  10. 由javascript中的this指针所想到的

    初次结识 this 指针,是在学 <<C++ Primer Plus>>这本书的时候(这本书勉强读了一二遍,之后转学 html+css+js了,不过这是后话). 依稀记得书中举 ...