Android中View框架的工作机制中,主要有三个过程:

1、View树的测量(measure)Android View框架的measure机制
     2、View树的布局(layout) Android View框架的layout机制
     3、View树的绘制(draw)Android View框架的draw机制

View框架的工作流程为:测量每个View大小(measure)-->把每个View放置到相应的位置(layout)-->绘制每个View(draw)。

1、系统为什么要有measure过程?

开发人员在绘制UI的时候,基本都是通过XML布局文件的方式来配置UI,而每个View必须要设置的两个群属性就是layout_width和layout_height,这两个属性代表着当前View的尺寸。

官方文档截图:

所以这两个属性的值是必须要指定的,这两个属性的取值只能为三种类型:

                 1、固定的大小,比如100dp。

2、刚好包裹其中的内容,wrap_content。

3、想要和父布局一样大,match_parent / fill_parent。

由于Android希望提供一个更优雅的GUI框架,所以提供了自适应的尺寸,也就是 wrap_content 和 match_parent 。

试想一下,那如果这些属性只允许设置固定的大小,那么每个View的尺寸在绘制的时候就已经确定了,所以可能都不需要measure过程。但是由于需要满足自适应尺寸的机制,所以需要一个measure过程。

2、measure过程都干了点什么事?

由于上面提到的自适应尺寸的机制,所以在用自适应尺寸来定义View大小的时候,View的真实尺寸还不能确定。但是View尺寸最终需要映射到屏幕上的像素大小,所以measure过程就是干这件事,把各种尺寸值,经过计算,得到具体的像素值。measure过程会遍历整棵View树,然后依次测量每个View真实的尺寸。具体是每个ViewGroup会向它内部的每个子View发送measure命令,然后由具体子View的onMeasure()来测量自己的尺寸。最后测量的结果保存在View的mMeasuredWidth和mMeasuredHeight中,保存的数据单位是像素。

3、对于自适应的尺寸机制,如何合理的测量一颗View树?

系统在遍历完布局文件后,针对布局文件,在内存中生成对应的View树结构,这个时候,整棵View树种的所有View对象,都还没有具体的尺寸,因为measure过程最终是要确定每个View打的准确尺寸,也就是准确的像素值。但是刚开始的时候,View中layout_width和layout_height两个属性的值,都只是自适应的尺寸,也就是match_parent和wrap_content,这两个值在系统中为负数,所以系统不会把它们当成具体的尺寸值。所以当一个View需要把它内部的match_parent或者wrap_content转换成具体的像素值的时候,他需要知道两个信息。

        1、针对于match_parent,父布局当前具体像素值是多少,因为match_parent就是子View想要和父布局一样大。

2、针对wrap_content,子View需要根据当前自己内部的content,算出一个合理的能包裹所有内容的最小值。但是如果这个最小值比当前父布局还大,那不行,父布局会告诉你,我只有这么大,你也不应该超过这个尺寸。

由于树这种数据结构的特殊性,我们在研究measure的过程时,可以只研究一个ViewGroup和2个View的简单场景。大概示意图如下:

也就是说,在measure过程中,ViewGroup会根据自己当前的状况,结合子View的尺寸数据,进行一个综合评定,然后把相关信息告诉子View,然后子View在onMeasure自己的时候,一边需要考虑到自己的content大小,一边还要考虑的父布局的限制信息,然后综合评定,测量出一个最优的结果。

4、那么ViewGroup是如何向子View传递限制信息的?

 谈到传递限制信息,那就是MeasureSpec类了,该类贯穿于整个measure过程,用来传递父布局对子View尺寸测量的约束信息。简单来说,该类就保存两类数据。
   1、子View当前所在父布局的具体尺寸。
   2、父布局对子View的限制类型。
        那么限制类型又分为三种类型:
                1、UNSPECIFIED,不限定。意思就是,子View想要多大,我就可以给你多大,你放心大胆的measure吧,不用管其他的。也不用管我传递给你的尺寸值。(其实    Android高版本中推荐,只要是这个模式,尺寸设置为0)
                2、EXACTLY,精确的。意思就是,根据我当前的状况,结合你指定的尺寸参数来考虑,你就应该是这个尺寸,具体大小在MeasureSpec的尺寸属性中,自己去查看吧,你也不要管你的content有多大了,就用这个尺寸吧。
                3、AT_MOST,最多的。意思就是,根据我当前的情况,结合你指定的尺寸参数来考虑,在不超过我给你限定的尺寸的前提下,你测量一个恰好能包裹你内容的尺寸就可以了。

源代码分析

在View的源代码中,提取到了下面一些关于measure过程的信息。

我们知道,整棵View树的根节点是DecorView,它是一个FrameLayout,所以它是一个ViewGroup,所以整棵View树的测量是从一个ViewGroup对象的measure方法开始的。

View:
1、measure

/** 开始测量一个View有多大,parent会在参数中提供约束信息,实际的测量工作是在onMeasure()中进行的,该方法会调用onMeasure()方法,所以只有onMeasure能被也必须要被override */
public final void measure(int widthMeasureSpec, int heightMeasureSpec);

父布局会在自己的onMeasure方法中,调用child.measure ,这就把measure过程转移到了子View中。

2、onMeasure

/** 具体测量过程,测量view和它的内容,来决定测量的宽高(mMeasuredWidth  mMeasuredHeight )。该方法中必须要调用setMeasuredDimension(int, int)来保存该view测量的宽高。 */

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec);

子View会在该方法中,根据父布局给出的限制信息,和自己的content大小,来合理的测量自己的尺寸。

3、setMeasuredDimension

/** 保存测量结果 */

protected final void setMeasuredDimension(int measuredWidth, int measuredHeight);

当View测量结束后,把测量结果保存起来,具体保存在mMeasuredWidth和mMeasuredHeight中。

ViewGroup:

1、measureChildren

/** 让所有子view测量自己的尺寸,需要考虑当前ViewGroup的MeasureSpec和Padding。跳过状态为gone的子view */
protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec);-->getChildMeasureSpec()-->child.measure();

测量所有的子View尺寸,把measure过程交到子View内部。

2、measureChild

/** 测量单个View,需要考虑当前ViewGroup的MeasureSpec和Padding。 */
protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec);-->getChildMeasureSpec()-->child.measure();

对每一个具体的子View进行测量。

3、measureChildWithMargins

/** 测量单个View,需要考虑当前ViewGroup的MeasureSpec和Padding、margins。 */
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed);-->getChildMeasureSpec()-->child.measure();

对每一个具体的子View进行测量。但是需要考虑到margin等信息。

4、getChildMeasureSpec

/** measureChildren过程中最困难的一部分,为child计算MeasureSpec。该方法为每个child的每个维度(宽、高)计算正确的MeasureSpec。目标就是把当前viewgroup的MeasureSpec和child的LayoutParams结合起来,生成最合理的结果。 比如,当前ViewGroup知道自己的准确大小,因为MeasureSpec的mode为EXACTLY,而child希望能够match_parent,这时就会为child生成一个mode为EXACTLY,大小为ViewGroup大小的MeasureSpec。  */

public static int getChildMeasureSpec(int spec, int padding, int childDimension);

根据当前自身的状况,以及特定子View的尺寸参数,为特定子View计算一个合理的限制信息。

源代码:

View的measure机制的更多相关文章

  1. Android View框架的measure机制

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

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

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

  3. Android 中View的绘制机制源代码分析 三

    到眼下为止,measure过程已经解说完了,今天開始我们就来学习layout过程.只是在学习layout过程之前.大家有没有发现我换了编辑器,哈哈.最终下定决心从Html编辑器切换为markdown编 ...

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

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

  5. Android 中View的绘制机制源代码分析 一

    尊重原创: http://blog.csdn.net/yuanzeyao/article/details/46765113 差点儿相同半年没有写博客了,一是由于工作比較忙,二是认为没有什么内容值得写, ...

  6. Android 中View的绘制机制源代码分析 二

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/46842891 本篇文章接着上篇文章的内容来继续讨论View的绘制机制,上篇文章中我们主要解说 ...

  7. Android View的绘制机制前世今生---前世

    就像上个文章说的,触摸事件的传递机制是从外层到内层的过程. 我们想来看看这个页面里面的层级关系: 以下我们就用what-how-why三部曲的方式来分析View的绘制过程. 由于篇幅很大,所以分几篇来 ...

  8. Atitit View事件分发机制

    1. Atitit View事件分发机制 1. Atitit View事件分发机制1 1.1. 三个关键方法 dispatchTouchEvent onInterceptTouchEvent onTo ...

  9. 普通View的measure流程

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

随机推荐

  1. 课程一(Neural Networks and Deep Learning),第一周(Introduction to Deep Learning)—— 0、学习目标

    1. Understand the major trends driving the rise of deep learning.2. Be able to explain how deep lear ...

  2. OSGI动态加载删除Service bundle

    OSGi模块化框架是很早就出来的一个插件化框架,最早Eclipse用它而出名,但这些年也没有大热虽然OSGi已经发布了版本1到版本5.现在用的最多的,也是本文讲述基于的是Equinox的OSGi实现, ...

  3. 【转】多线程:C#线程同步lock,Monitor,Mutex,同步事件和等待句柄(上)

    本篇从Monitor,Mutex,ManualResetEvent,AutoResetEvent,WaitHandler的类关系图开始,希望通过 本篇的介绍能对常见的线程同步方法有一个整体的认识,而对 ...

  4. 利用latex制作个人简历

    转自: http://www.cnblogs.com/panpei/ 前些日子,有点无聊,就在网上逛逛技术大牛的blogs,发现很多大牛都喜欢用pdf版式的简历,发现这种版式的简历排版非常漂亮简洁.深 ...

  5. (转)Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring

    Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring Mybatis在与Spring集成的时候可以配置MapperFactoryBea ...

  6. Spring学习之路-SpringBoot简单入门

    简单讲SpringBoot是对spring和springMVC的二次封装和整合,新添加了一些注解和功能,不算是一个新框架. 学习来源是官方文档,虽然很详细,但是太墨迹了… 地址:https://doc ...

  7. [转]Webpack 入门教程

    本文转自:http://www.runoob.com/w3cnote/webpack-tutorial.html Webpack 是一个前端资源加载/打包工具.它将根据模块的依赖关系进行静态分析,然后 ...

  8. 基于spring boot的定时器

    首先,搭建好一个springboot项目 方法一:通过springboot自带入口来开启定时器. 首先我们都知道,springboot有一个自己的入口,也就是@SpringBootApplicatio ...

  9. JS DOM 操作 项目总结 【超链接】【数列】【span】

      超链接   每次定义链接样式时务必确认定义的顺序,link--visited--hover-active,也就是我们常说到的LoVe HAte原则(大写字母就是它们的首字母). “爱恨原则”(Lo ...

  10. SQL Server 数据库的鼠标操作

    在数据库中一些操作用鼠标进行可视化操作更方便快捷 一 SQL Server 开启 任务栏——任务管理器——服务——MSSQLSERVER 开启 我的电脑——控制面板——管理工具——服务——MSSQLS ...