【原创】Android View框架总结(三)View工作原理
- 测量/布局/绘制顺序
- 如何引起View的测量/布局/绘制?
- PerformTraversales()
- ViewRoot
- View工作基本流程
- MeasureSpec
- SpecMode
- MeasureSpec和LayoutParams
- RootMeasureSpec
- MeasureSpec
测量/布局/绘制顺序
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工作原理的更多相关文章
- Android显示框架:自定义View实践之绘制篇
文章目录 一 View 二 Paint 2.1 颜色处理 2.2 文字处理 2.3 特殊处理 三 Canvas 3.1 界面绘制 3.2 范围裁切 3.3 集合变换 四 Path 4.1 添加图形 4 ...
- 【原创】NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战
前言 本文将演示一个iOS客户端程序,通过UDP协议与两个典型的NIO框架服务端,实现跨平台双向通信的完整Demo.服务端将分别用MINA2和Netty4进行实现,而通信时服务端你只需选其一就行了.同 ...
- 分布式计算框架学习笔记--hadoop工作原理
(hadoop安装方法:http://blog.csdn.net/wangjia55/article/details/53160679这里不再累述) hadoop是针对大数据设计的一个计算架构.如果你 ...
- Android消息机制之ThreadLocal的工作原理
来源: http://blog.csdn.net/singwhatiwanna/article/details/48350919 很多人认为Handler的作用是更新UI,这说的的确没错,但是更新UI ...
- 转载:【Oracle 集群】RAC知识图文详细教程(三)--RAC工作原理和相关组件
文章导航 集群概念介绍(一) ORACLE集群概念和原理(二) RAC 工作原理和相关组件(三) 缓存融合技术(四) RAC 特殊问题和实战经验(五) ORACLE 11 G版本2 RAC在LINUX ...
- EF框架的三种工作方式
EF框架step by step(1)—Database-First EF框架step by step(2)—Model-First EF框架step by step(3)—Code-First 通过 ...
- Android 网络通信框架Volley(三)
NetworkImageView 分析:public class NetworkImageView extends ImageView 他继承自ImageView,并且添加了一个新方法: public ...
- android学习11——Handler,Looper,MessageQueue工作原理
Message是Handler接收和处理的消息对象. 每个线程只能拥有一个Looper.它的loop方法读取MessageQueue中的消息,读到消息之后就把消息交给发送该消息的Handler进行处理 ...
- ZooKeeper之(三)工作原理
3.1 系统架构 ZooKeeper集群是由多台机器组成的,每台机器都充当了特定的角色,各种角色在协作过程中履行自己的任务,从而对外提供稳定.可靠的服务. 由上图可知,ZooKeeper集群由多台机器 ...
- [原创]Android Studio的Instant Run(即时安装)原理分析和源码浅析
Android Studio升级到2.0之后,新增了Instant Run功能,该功能可以热替换apk中的部分代码,大幅提高测试安装的效率. 但是,由于我的项目中自定义了一些ClassLoader,当 ...
随机推荐
- Struts之准备工作
*Struts之需要准备的jar包: *Struts之xml配置文件: <?xml version="1.0" encoding="UTF-8"?> ...
- Python+Selenium练习篇之6-利用class name定位元素
有时候,我们在用firepath(不会的请点这里)查看元素的XPath信息,发现没有可以用来定位的id信息,这个时候我们就需要考虑用其他的可用的来定位元素.本文介绍如何通过元素节点中class nam ...
- git+jenkins持续集成二-jenkins定时构建语法:定时构建语法
构建位置:选择或创建工程_设置_构建触发器 1. 定时构建语法:* * * * * (五颗星,多个时间点,中间用逗号隔开)第一个*表示分钟,取值0~59第二个*表示小时,取值0~23第三个*表示一个月 ...
- 前端应该掌握的CSS实现多列等高布局
1.引言 我们在写页面的时候,有的时候会遇到多栏布局,每个栏目里面的内容有的时候可能不一样,这样就会导致每个栏目实际的高度也是不一样的,如果每个栏目有背景颜色的,就会导致每个栏目的底部是对不齐的,用户 ...
- allocator class
当分配一大块内存时,我们通常计划在这块内存上按需构造对象,这样的我们希望将内存分配和对象构造分离.但是通常的new关键字的分配的动态空间,有时候会造成一些浪费,更致命的是“如果一个类没有默认构造函数, ...
- 牛客网python试题-错误整理-20180711
######## >>>[3] in [1,2,3,4] False >>>3 in [1,2,3,4] True ######## x = (y = z + 1) ...
- aspx页面直接访问后台方法
在方法上面机上[WebMethod]就可以直接请求该方法了.
- 给出 中序&后序 序列 建树;给出 先序&中序 序列 建树
已知 中序&后序 建立二叉树: SDUT 1489 Description 已知一棵二叉树的中序遍历和后序遍历,求二叉树的先序遍历 Input 输入数据有多组,第一行是一个整数t (t& ...
- 为不是函数的对象 'dbo.xxxx' 提供了参数。如果这些参数要作为表提示,则需要使用 WITH 关键字
为不是函数的对象 'dbo.xxxxxx' 提供了参数.如果这些参数要作为表提示,则需要使用 WITH 关键字 犯错误原因:给视图加条件了.. 用.where(a=>a.ID=xxx.ID);
- maven国内镜像
<?xml version="1.0" encoding="UTF-8"?> <!--Licensed to the Apache Softw ...