`
mmdev
  • 浏览: 12894723 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

Android中mesure过程详解 (结合Android 4.0.4 最新源码)

 
阅读更多

如何遍历并绘制View树?之前的文章Android中invalidate() 函数详解(结合Android 4.0.4 最新源码)提到invalidate()最后会发起一个View树遍历的请求,并通过执行performTraersal()来响应该请求,performTraersal()正是对View树进行遍历和绘制的核心函数,内部的主体逻辑是判断是否需要重新测量视图大小(measure),是否需要重新布局(layout),是否重新需要绘制(draw)。measure过程是遍历的前提,只有measure后才能进行布局(layout)和绘制(draw),因为在layout的过程中需要用到measure过程中计算得到的每个View的测量大小,而draw过程需要layout确定每个view的位置才能进行绘制。下面我们主要来探讨一下measure的主要过程,相对与layout和draw,measure过程理解起来比较困难。

我们在编写layout的xml文件时会碰到layout_width和layout_height两个属性,对于这两个属性我们有三种选择:赋值成具体的数值,match_parent或者wrap_content,而measure过程就是用来处理match_parent或者wrap_content,假如layout中规定所有View的layout_width和layout_height必须赋值成具体的数值,那么measure其实是没有必要的,但是google在设计Android的时候考虑加入match_parent或者wrap_content肯定是有原因的,它们会使得布局更加灵活。

首先我们来看几个关键的函数和参数:

1、public final void measue(int widthMeasureSpec, int heightMeasureSpec);

2、protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec);

3、protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec)

4、protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec)

5、protected void measureChildWithMargins(View child,int parentWidthMeasureSpec, int widthUsed,int parentHeightMeasureSpec, int heightUsed)

接着我们来看View类中measure和onMeasure函数的源码:

由于函数原型中有final字段,那么measure根本没打算被子类继承,也就是说measure的过程是固定的,而measure中调用了onMeasure函数,因此真正有变数的是onMeasure函数,onMeasure的默认实现很简单,源码如下:

onMeasure默认的实现仅仅调用了setMeasuredDimension,setMeasuredDimension函数是一个很关键的函数,它对View的成员变量mMeasuredWidth和mMeasuredHeight变量赋值,而measure的主要目的就是对View树中的每个View的mMeasuredWidth和mMeasuredHeight进行赋值,一旦这两个变量被赋值,则意味着该View的测量工作结束。

对于非ViewGroup的View而言,通过调用上面默认的measure——>onMeasure,即可完成View的测量,当然你也可以重载onMeasure,并调用setMeasuredDimension来设置任意大小的布局,但一般不这么做,因为这种做法太“专政”,至于为何“专政”,读完本文就会明白

对于ViewGroup的子类而言,往往会重载onMeasure函数负责其children的measure工作,重载时不要忘记调用setMeasuredDimension来设置自身的mMeasuredWidth和mMeasuredHeight。如果我们在layout的时候不需要依赖子视图的大小,那么不重载onMeasure也可以,但是必须重载onLayout来安排子视图的位置,这在下一篇博客中会介绍。

再来看下measue(int widthMeasureSpec, int heightMeasureSpec)中的两个参数, 这两个参数分别是父视图提供的测量规格,当父视图调用子视图的measure函数对子视图进行测量时,会传入这两个参数,通过这两个参数以及子视图本身的LayoutParams来共同决定子视图的测量规格,在ViewGroup的measureChildWithMargins函数中体现了这个过程,稍后会介绍。

MeasureSpec参数的值为int型,分为高32位和低16为,高32位保存的是specMode,低16位表示specSize,specMode分三种:

1、MeasureSpec.UNSPECIFIED,父视图不对子视图施加任何限制,子视图可以得到任意想要的大小;

2、MeasureSpec.EXACTLY,父视图希望子视图的大小是specSize中指定的大小;

3、MeasureSpec.AT_MOST,子视图的大小最多是specSize中的大小。

以上施加的限制只是父视图“希望”子视图的大小按MeasureSpec中描述的那样,但是子视图的具体大小取决于多方面的。

ViewGroup中定义了measureChildren, measureChild, measureChildWithMargins来对子视图进行测量,measureChildren内部只是循环调用measureChild,measureChild和measureChildWithMargins的区别就是是否把margin和padding也作为子视图的大小,我们主要分析measureChildWithMargins的执行过程:

总的来看该函数就是对父视图提供的measureSpec参数进行了调整(结合自身的LayoutParams参数),然后再来调用child.measure()函数,具体通过函数getChildMeasureSpec来进行参数调整,过程如下:

getChildMeasureSpec的总体思路就是通过其父视图提供的MeasureSpec参数得到specMode和specSize,并根据计算出来的specMode以及子视图的childDimension(layout_width和layout_height中定义的)来计算自身的measureSpec,如果其本身包含子视图,则计算出来的measureSpec将作为调用其子视图measure函数的参数,同时也作为自身调用setMeasuredDimension的参数,如果其不包含子视图则默认情况下最终会调用onMeasure的默认实现,并最终调用到setMeasuredDimension,而该函数的参数正是这里计算出来的。

总结:从上面的描述看出,决定权最大的就是View的设计者,因为设计者可以通过调用setMeasuredDimension决定视图的最终大小,例如调用setMeasuredDimension(100, 100)将视图的mMeasuredWidth和mMeasuredHeight设置为100,100,那么父视图提供的大小以及程序员在xml中设置的layout_width和layout_height将完全不起作用,当然良好的设计一般会根据子视图的measureSpec来设置mMeasuredWidth和mMeasuredHeight的大小,已尊重程序员的意图。

分享到:
评论

相关推荐

    Leaflet.MeasureControl, 在地图上,用小叶控制mesure距离.zip

    Leaflet.MeasureControl, 在地图上,用小叶控制mesure距离 Leaflet.MeasureControl在地图上的mesure距离到距离。需要 Leaflet.Draw查看演示程序。安装npm install leaflet.measurecontrol用法作为映射

    Mesure.zip

    高德地图(第二篇)测量距离小工具中的源代码,欢迎下载.

    Convertisseur de mesure:转换不同的测量单位-开源

    该工具在VB.NET中编程,可转换时间,能量,长度,重量,面积,温度,速度或体积的单位。

    Measure Theory

    Good book for mesure theory.

    matlab自相关代码-aprl-env400-assignment:分配EPFL的ENV-400(空气污染和气候变化)硕士课程

    为此,本模块介绍了用于生成(单个变量或其关系的)时空模式的简洁描述的方法,并解释了由于排放和大气过程而引起的浓度变化。 我们引入了一些有用的概念来构造和操作此类数据集,这将有助于对假设的探索性分析和...

    sketch-measure-cli:用于草图测量插件的CLI工具

    Sketch-Mesure-Cli 是的绝佳插件。 有时我想将它嵌入到带有cli的工作流中,这确实很难。 sketchtool和都不sketchtool -Measure处理skech文件的全部功能。 最后,我编写了sketch-messure-cli以帮助在cli中使用Sketch-...

    ecoIndexPlugin:Firefox扩展-Ecoindex

    Démarrerla Mesure en cliquant sur l'icone Ei et puis sur le bouton“开始” 留置保险单据 Une fois la pagechargée,“ Licone l'icone Ei et puis sur le bouton”“停止” Cliquer sur le bouton查看结果 ...

    FABRIGOULE_JOLY_PROJET_IN204

    Nécessitedereconnaîtrele nombre de mesure参数页面 Jouer la partition par文书。 Compliqués'il s'agit d'une图片 最优惠的组织者(Systèmedeàà5étoiles) 安装DEV git子模块init git子模块更新 对于...

    marcwrobel.github.io:网站网站来源

    网站上的资源 。 精神病学 站点网站利用站点上的静态站点 et esthébergé。 利用aussi: pour la mise en forme, ... Apportez套房VOS修改等前期visualisez莱AU皮毛等人MESURE 。 Commitez enfin vos chang

    Donnees-Seine-Yonne

    Néanmoins,最有可能的décalées商标,meer erreur de mesure,par faute de frappe(请到达assez souvent!)或ens lors du dessin pour la出版物。 Dans ce cas,计划制作和发行带有协调性的ausystè...

    JavaClassProfiler:Java类探查器-开源

    简约的Java事件探查器,它使用工具和asm库来对方法所花费的时间进行度量。 Mesure一直有效到微秒,非常逼真的毫秒。 ui允许导出,远程连接和多个连接。

Global site tag (gtag.js) - Google Analytics