文档章节

Android View 的工作原理(包含对 DecorView 和 ViewRoot 的简单介绍)

天王盖地虎626
 天王盖地虎626
发布于 06/21 10:51
字数 1589
阅读 4
收藏 1

    什么是 View ?

      View 是 Android 中所有控件的基类,View 可以是单个控件,也可以是由多个控件组成的一组控件。ViewGroup 里面可以有子 View,子 View 里面也可以有 ViewGroup。

    什么是 ViewRoot、DecorView ?

      View 有三大流程,measure、layout、draw,了解并熟悉其三大流程对于我们进行 Android 开发有着极其重要的作用。在熟悉三大流程之前,先介绍一下 ViewRoot 和 DecorView 的概念。

      Activity 内部 是组合了一个 Window 对象,Activity 所有的事件都是交给 Window 来处理的,但是 Window 是一个抽象类,处理事务具体的操作就只能交给它的实现类,也就是 PhoneWindow,PhoneWindow 就会把事件传给这个 DecorWindow,这个 DecorWinow 是应用窗口的根容器,也就是个顶级 View,其实是个 FrameLayout。这个根容器一般情况下都只有唯一一个子 View ,就是一个垂直的 LinearLayout,上下两部分分别是标题栏和内容栏。而 ViewRoot 是 View 树的管理者,它的成员变量 mView 对应的就是一个布局的根 View,ViewRoot 是 View 和 WindowManger 的桥梁,也就是 DecorView 和 WindowManger 的纽带,对应的是 ViewRootImpl 类。当 Activity 创建完成后,就会创建 ViewRootImpl 对象,将 DecorView 添加到 Window 中,并将 DecorView 和 ViewRootImpl 建立关联。

      View 的三大流程就是从 ViewRoot 的 performTraversals 方法开始的。该方法会依次调用 performMeasure、performLayout、performDraw 三个方法,来完成顶级 View 的三大流程。三个方法又会分别调用 onMeasure、onLayout、onDraw 方法来完成对子 View 的 measure、layout、draw。接着子元素会重复父容器的 measure、layout、draw。来完成整个 View 树的三大流程。measure 决定 View 的 宽高、layout 确定四个顶点的位置、draw 则会将内容呈现在屏幕上。

    什么是 MeasureSpec ?

      为了更好的了解 View 的测量过程,我们还需要了解 MeasureSpec。MeasureSpec 在很大程度上决定了一个 View 的尺寸规格。如果对于 DecorView,其 View 的 MeasureSpec 就是由窗口的大小和自身的LayoutParams 所决定的,但是如果是一个子 View,其 MeasureSpec 则是由父容器的 MeasureSpec 和自身的 LayoutParams 所共同决定的。

      MeasureSpec 是一个32位 int 值,高两位代表的是测量模式 SpecMode,低30位代表的是某种测量模式下的规格大小 SpecSize。

      SpecMode 有三类:UNSPECIFIED、EXACTLY、AT_MOST。

      UNSPECIFIED:父容器不对子 View 做限制,想要多大就多大。

      EXACTLY:父容器检测出 View 的精确大小,这个时候 View 的最终大小就是 SpecSize 所指定的值。对应的是 LayoutParams 中的 match_parent 或 具体数值。

      AT_MOST:父容器指定一个大小 SpecSize,子 View 的大小按照自身要求决定,但是不能超过 SpecSize,对应 LayoutParams 中的 wrap_content。

    View 的三大流程

    measure 过程:
      measure 过程要分清情况,当要测量的只是一个原始的 View 时,那么只通过 measure 就可以完成其测量过程,但是如果是一个 ViewGroup,就需要遍历测量所有的子 View。
      下面是 View 的 onMeasure 方法:


      它调用了 setMaasureDimension() 方法来设置 View 宽高的测量值,那么 getDefaSize() 方法又是干嘛的呢?


      它是通过测量模式来返回测量得出的值。当测量模式为 UNSPECIFIED 时,测量值就为 result,也就是 getSuggestedMinimumWidth() 或者 getSuggestedMinimumHeight() 返回的值。当测量模式为 AT_MOST 和 EXACTLY 时,返回的大小就是 MeasureSpec 中测量得到的 SpecSize。

      那么 getSuggestedMinimumWidth() 和 getSuggestedMinimumHeight() 方法又在干什么呢?

 

      这两个方法会判断当前 View 的背景是不是为空,为空就返回 mMinWidth/mMinHeight(即为 minWidth 和 minHeight 属性设置的值),不为空就返回 mMinWidth/mMinHeight 和 背景的 getMinimumWidth()/getMinimumHeight() 返回值中的较大的那个值。

      而 ViewGroup 的 measure 过程如下:

      对于 ViewGroup 来说,不仅需要测量自身,还需要测量所有的子 View。和 View 不同的是,ViewGroup 是一个抽象类,所以没有重写 View 的 onMeasure() 方法,而是提供了 measureChildren() 的方法。


     该方法会遍历 ViewGroup 的每一个 Child,然后调用 measureChild() 方法。


      该方法会得到子元素的 LayoutParams,再通过 getChildMeasureSpec 来获取子元素的 MeasureSpec,然后调用 View 的 measure() 方法进行测量。
    layout 过程:

      layout 过程是为了确定 View 的位置,在 ViewGroup 位置被确定后,它会遍历并确定所有子元素的位置。

      下面是 View 的 layout() 方法:


      

      layout() 方法首先会通过 setFrame() 方法来设定四个顶点的位置,四个顶点一旦确定,View 在父容器中的位置也就确定了,接着会调用 onLayout() 方法。这个方法是父容器确定子元素的位置,因为布局选择的不同,确认的方式也会不一样,所以在 View 和 ViewGroup 中都没有真正实现 onLayout()。具体的 onLayout() 实现要看选择的布局方式。

      ViewGroup 中,会使用 onLayout() 方法遍历所有子元素并调用其 layout() 方法,在 layout() 方法中又会调用 onLayout() 方法,直到确定完整个 View 树的位置。
    draw 过程:

      draw 过程是将 View 绘制到屏幕上,View 源码中的 draw() 方法比较长,就不复制到这了,感兴趣的小伙伴可以自己去看看。

      draw() 方法主要有四个部分:绘制背景、绘制自己、绘制 children、绘制装饰。

      绘制过程的传递是通过 dispatchDraw() 方法来实现的,会遍历所有子元素的 draw() 方法,一层一层绘制完整个 View 树。

      View 还有一个特殊方法,setWillNotDraw(),如下:


      表示如果 View 不需要绘制任何东西时,会将 flags 设置为 true,然后进行相应的优化。默认情况下,View 没有启用这个优化标志位,但是 ViewGroup 默认启用了。当一个自定义 View 继承自 ViewGroup 并且本身不需要绘制时,可以开启这个标志位方便后续优化,如果需要绘制,就得显性关闭 WILL_NOT_DRAW 这个标志位。
 

本文转载自:https://blog.csdn.net/Young_Time/article/details/80266947

天王盖地虎626

天王盖地虎626

粉丝 32
博文 527
码字总数 20708
作品 0
南京
私信 提问
Android自定义View基础:ViewRoot、DecorView & Window的简介

前言 自定义View原理是Android开发者必须了解的基础,在了解自定义View之前,你需要有一定的知识储备。 今天,本文将全面解析关于自定义View中基础:ViewRoot、DecorView & Window,希望你们...

Carson_Ho
05/30
0
0
Android窗口机制(一)初识Android的窗口结构

Android窗口机制系列 Android窗口机制(一)初识Android的窗口结构 Android窗口机制(二)Window,PhoneWindow,DecorView,setContentView源码理解 Android窗口机制(三)Window和WindowMan...

亭子happy
02/26
33
0
Android控件TextView的实现原理分析

在前面一个系列的文章中,我们以窗口为单位,分析了WindowManagerService服务的实现。同时,在再前面一个系列的文章中,我们又分析了窗口的组成。简单来说,窗口就是由一系列的视图按照一定的...

Luoshengyang
2018/06/26
0
0
初始Android Framework(框架)方面的知识(一)

初始Android Framework(框架)方面的知识 介绍Android Framework(框架)是什么? Android Framework(框架)有什么? 首先介绍一下服务端都有哪些重要的东西: 下面介绍一下客户端比较重要...

天王盖地虎626
06/21
42
0
Android进阶——Android弹窗组件工作机制之Dialog、DialogFragment

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_30379689/article/details/86597623 前言 Android在DialogFragment推出后,就已经不推荐继续使用Dialog,可...

Hensen_
01/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

springboot2.0 maven打包分离lib,resources

springboot将工程打包成jar包后,会出现获取classpath下的文件出现测试环境正常而生产环境文件找不到的问题,这是因为 1、在调试过程中,文件是真实存在于磁盘的某个目录。此时通过获取文件路...

陈俊凯
今天
6
0
BootStrap

一、BootStrap 简洁、直观、强悍的前端开发框架,让web开发更加迅速、简单 中文镜像网站:http://www.bootcss.com 用于开发响应式布局、移动设备优先的WEB项目 1、使用boot 创建文件夹,在文...

wytao1995
今天
10
0
小知识:讲述Linux命令别名与资源文件的区别

别名 别名是命令的快捷方式。为那些需要经常执行,但需要很长时间输入的长命令创建快捷方式很有用。语法是: alias ppp='ping www.baidu.com' 它们并不总是用来缩短长命令。重要的是,你将它...

老孟的Linux私房菜
今天
8
0
《JAVA核心知识》学习笔记(6. Spring 原理)-5

它是一个全面的、企业应用开发一站式的解决方案,贯穿表现层、业务层、持久层。但是 Spring 仍然可以和其他的框架无缝整合。 6.1.1. Spring 特点 6.1.1.1. 轻量级 6.1.1.2. 控制反转 6.1.1....

Shingfi
今天
8
0
Excel导入数据库数据+Excel导入网页数据【实时追踪】

1.Excel导入数据库数据:数据选项卡------>导入数据 2.Excel导入网页数据【实时追踪】:

东方墨天
今天
11
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部