转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52180375

  • 测量/布局/绘制顺序
  • 如何引起View的测量/布局/绘制?
  • PerformTraversales()
  • ViewRoot
  • View工作基本流程
    • MeasureSpec

      • SpecMode
      • MeasureSpec和LayoutParams
      • RootMeasureSpec

测量/布局/绘制顺序

View什么时候测量/布局/绘制?

Invalidate,requestLayout,requestFocus最终都会调用到ViewRoot中的schedulTraversale(),该函数发起一个异步消息,消息处理中调用performTraversals()方法对整个View进行遍历。

  • Invalidate

    请求重绘view树,假如视图大小没有变化就不会调用layout(),只绘制那些需要重绘的视图,谁请求就重绘谁(ViewGroup调用就重绘整个ViewGroup)
  • requestLayout

    只对view树重新layout,会导致调用measure和layout过程,不会调用draw()过程
  • requestFocus

    请求view树的draw过程,但只绘制需要重绘的视图
  • setVisibility()

    当View可视状态在INVISIBLE转换VISIBLE时,会间接调用invalidate()方法, 当View的可视状态在INVISIBLE/ VISIBLE 转换为GONE状态时,会间接调用requestLayout() 和invalidate方法。同时,由于整个个View树大小发生了变化,会请求measure()过程以及draw()过程,同样地,只绘制需要“重新绘制”的视图

ViewRoot

一个Window中View根节点DecorView, 它的mParent称为ViewRoot, 对应ViewRootImpl类, 它不是View的子类, 而是个ViewParent. ViewRootImpl是连接Window和DecorView的纽带, View的焦点, 按键, 布局, 渲染等流程都是从ViewRoot中开始的.

View绘制流程从requestLayout触发, View系统中所有会改变布局的方法都会触发requestLayout, 如TextView改变文字, ViewGroup添加View等.

View.java

 public void requestLayout() {
        mPrivateFlags |= PFLAG_FORCE_LAYOUT;
        mPrivateFlags |= PFLAG_INVALIDATED;

        if (mParent != null && !mParent.isLayoutRequested()) {
            mParent.requestLayout();
        }
  }

View的requestLayout最终调用到ViewRootImpl

ViewRootImpl.java

public void requestLayout() {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
}

从scheduleTraversals名字来看, requestLayout只是触发一个异步的任务. 事实上, View真正的绘制流程是从ViewRootImpl的performTraversals方法开始, 里面会经过measure, layout和draw三个过程. 其中measure用来测量View的宽高, layout用来确定View的位置, 而draw负责渲染View到屏幕上. 大致流程如下:

performTraversals会依次调用performMeasure, performlayout和performDraw方法. 父容器measure方法会调用onMeasure, onMeasure方法会对所有子元素进行measure过程, 以此遍历完整个View树. layout和draw流程类似.

measure过程计算View的宽高, 先看measure方法

public final void measure(int widthMeasureSpec, int heightMeasureSpec)

参数measureSpec是父容器传的对View的尺寸规格限制. 根节点DecorView的measureSpec在ViewRoot中计算出.

MeasureSpec

MeasureSpec字面上可以理解为尺寸规格, 测量过程中父容器会根据自己的MeasureSpec和子View的LayoutParams转换成对应的MeasureSpec, 子View根据这个MeasureSpec来计算出宽高, 因此我理解MeasureSpec是父容器对子元素的尺寸限制, 这样对下面的源码就好理解

View.java

  • 使int 类型的高两位表示模式的实际值,其余30位代表长或宽的实际值—-可以是WRAP_CONTENT、MATCH_PARENT或具体大小exactly size。
  • 通过掩码MODE_MASK进行与运算 “&”,取得模式(mode)以及长或宽(value)的实际值。
  • 最高两位表示模式,后30位表示组件大小的值

    最高两位是00的时候表示”未指定模式”。即MeasureSpec.UNSPECIFIED

    最高两位是01的时候表示”’精确模式”。即MeasureSpec.EXACTLY

    最高两位是11的时候表示”最大模式”。即MeasureSpec.AT_MOST

SpecMode

SpecMode有三种

  • UNSPECIFIED: 父容器不对View做任何限制. 一般在系统内部使用, 用于如ScrollView中, 或者需要多次测量来决定最终值的ViewGroup
  • EXACTLY: 父容器已经知道View精确大小是SpecSize, 或者限制View大小就是SpecSize
  • AT_MOST: 父容器指定View最大size是SpecSize, 一般在LayoutParams中是wrap_content或match_parent时使用.

MeasureSpec和LayoutParams

上面提到子View的MeasureSpec是根据LayoutParams和父容器的MeasureSpec转换来的, 虽然我们可以自己写转换算法, 但是系统里面已经提供了完善的算法. 除了DecorView的MeasureSpec是ViewRootImpl构造出来的, 其他View的转换方法都一样.

ViewGroup.java

上述方法就是对子元素进行measure的, 在measure之前通过getChildMeasureSpec方法得到子元素的MeasureSpec.

ViewGroup.java

上面的方法就是根据父容器的MeasureSpec结合View的LayoutParams转换子元素的MeasureSpec

方法中三个参数意义

  • spec: 父容器的MeasureSpec(这个未必是父容器的measure方法传入的MeasureSpec, 也可以根据情况构造一个)
  • padding: 父容器中已经被占用的空间, 如FrameLayout的padding值, LinearLayout前面View占据的空间等
  • childDimension: 子元素期望的size(或wrap_content/match_parent)

RootMeasureSpec

根节点View的MeasureSpec在performTraversals中得出. 先计算出窗口的最大可能尺寸desiredWindowWidth/desiredWindowHeight, 然后调用measureHierarchy方法来进入measure流程.:

ViewRootImpl.java

再看getRootMeasureSpec方法实现:

ViewRootImpl.java

DecorView的MeasureSpec根据窗口的LayoutParams按照如下规则生成

  • match_parent 明确大小就是窗口大小
  • wrap_content 最大不超过窗口大小
  • 固定大小 明确大小就是LayoutParams指定的值

至此,view的工作原理到此结束了,接下来就是view的布局流程。见下篇

第一时间获得博客更新提醒,以及更多Android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码,即可关注。

Android View框架总结(三)View工作原理的更多相关文章

  1. Android显示框架:自定义View实践之绘制篇

    文章目录 一 View 二 Paint 2.1 颜色处理 2.2 文字处理 2.3 特殊处理 三 Canvas 3.1 界面绘制 3.2 范围裁切 3.3 集合变换 四 Path 4.1 添加图形 4 ...

  2. 分布式计算框架学习笔记--hadoop工作原理

    (hadoop安装方法:http://blog.csdn.net/wangjia55/article/details/53160679这里不再累述) hadoop是针对大数据设计的一个计算架构.如果你 ...

  3. Android消息机制之ThreadLocal的工作原理

    来源: http://blog.csdn.net/singwhatiwanna/article/details/48350919 很多人认为Handler的作用是更新UI,这说的的确没错,但是更新UI ...

  4. 转载:【Oracle 集群】RAC知识图文详细教程(三)--RAC工作原理和相关组件

    文章导航 集群概念介绍(一) ORACLE集群概念和原理(二) RAC 工作原理和相关组件(三) 缓存融合技术(四) RAC 特殊问题和实战经验(五) ORACLE 11 G版本2 RAC在LINUX ...

  5. EF框架的三种工作方式

    EF框架step by step(1)—Database-First EF框架step by step(2)—Model-First EF框架step by step(3)—Code-First 通过 ...

  6. android学习11——Handler,Looper,MessageQueue工作原理

    Message是Handler接收和处理的消息对象. 每个线程只能拥有一个Looper.它的loop方法读取MessageQueue中的消息,读到消息之后就把消息交给发送该消息的Handler进行处理 ...

  7. ZooKeeper之(三)工作原理

    3.1 系统架构 ZooKeeper集群是由多台机器组成的,每台机器都充当了特定的角色,各种角色在协作过程中履行自己的任务,从而对外提供稳定.可靠的服务. 由上图可知,ZooKeeper集群由多台机器 ...

  8. Android 网络通信框架Volley(三)

    NetworkImageView 分析:public class NetworkImageView extends ImageView 他继承自ImageView,并且添加了一个新方法: public ...

  9. Git:三、工作原理

    首先,我们对工作区也就是文件夹中的文档进行修改. 然后,把修改并需要存档的文档用add命令放到暂存区,并且可以放很多文档. 最后,一个阶段的工作告一段落,使用commit命令把暂存区的内容一股脑存到G ...

  10. 汇编入门三-CPU工作原理

    本文为读书笔记,个人总结与摘抄自<汇编语言 第二版> 1.CPU从内存中读取数据,首先要获得存储单元的地址. 2.指明进行的操作,如存储或者读写 所以,CPU要进行操作总结为: 1.存储单 ...

随机推荐

  1. ●POJ 2187 Beauty Contest

    题链: http://poj.org/problem?id=2187 题解: 计算几何,凸包,旋转卡壳 一个求凸包直径的裸题,旋转卡壳入门用的. 代码: #include<cmath> # ...

  2. ●BZOJ 2329 [HNOI2011]括号修复.cpp

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2329 题解: Splay 类似 BZOJ 2329 [HNOI2011]括号修复 只是多了一 ...

  3. hdu3487 splay树

    Play with Chain Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  4. hdu 3473 划分树

    Minimum Sum Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Tot ...

  5. poj2947 高斯消元

    Widget Factory Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 5218   Accepted: 1802 De ...

  6. Python的序列类型——List

    List 列表 List,本质是一个链表,从链表的实现角度来讲,链表的每一个结点都存放着值和指向下一个节点的指针. 因此链表在内存的存储可以是不连续的,它是一种高效的数据结构.因此列表与字符串的区别是 ...

  7. Git与Github的基本概念

    git git是一个分布式版本控制系统,在这里就要介绍一下什么是版本控制:参考至维基百科 版本控制(Revision control)是维护工程蓝图的标准作法,能追踪工程蓝图从诞生一直到定案的过程.此 ...

  8. jquery easyui datagrid 编辑行 类型combobox

    完成编辑瞬间datagrid中显示的是combobox的value 而非text var rows=$('#tb1').datagrid('getRows'); for(var i=0;i<ro ...

  9. mysql insert插入时实现如果数据表中主键重复则更新,没有重复则插入的四种方法

    [CSDN下载] Powerdesigner 设计主键code不能重复等问题 [CSDN博客] Oracle中用一个序列给两个表创建主键自增功能的后果 [CSDN博客] MySQL自增主键删除后重复问 ...

  10. 软件测试assert

    之前实习做过一段时间测试,现做个总结: 实习测试的是一款CM系统(case 系统),来记录IT部门处理的维修,服务,反馈,预定服务等case:b/s架构,人少小项目,实习时间短,去了已经快完工,主要测 ...