Android中View的绘制过程

1. 概述

为了分析理解View的绘制过程,首先了解下图内容。

 Android 中 Activity 是作为应用程序的载体存在,代表着用户界面,提供窗口来绘制各种视图。

一个Activity包含一个Window,Window是一个抽象基类,是Activity和整个View系统交互的接口,只有一个子类实现类PhoneWindow,提供了一系列窗口的方法,比如设置背景,标题等。

一个PhoneWindow对应一个DecorView和一个ViewRootlmpl,DecorView是ViewTree里面的顶层布局,是继承FrameLayout,包含两个字View,一个id=statusBarBackground(状态栏)的View和LineaLayout,LineaLayout里面包含title和contentView,title是TitleBar或者ActionBar,contentView是FrameLayout并通过activity里面的setContentView()方法把界面布局加载进来,contentView中包含一系列的ViewGroup和View。

2.Window

Window即窗口,android.view.Window这个抽象类,是一个宏观的思想,它是屏幕上用于绘制各种UI元素及响应用户输入事件的一个矩形区域,独立绘制,不与其他界面相互影响,不会触发其他界面的输入事件。

在Android系统中,窗口是独占一个Surface实例的显示区域,每个窗口的Surface由WindowManagerService分配。我们可以把Surface看作一块画布,应用可以通过Canvas或OpenGL在其上面作画。画好之后,通过SurfaceFlinger将多块Surface按照特定的顺序(即Z-order)进行混合,而后输出到FrameBuffer中,这样用户界面就得以显示。

PhoneWindow这个类是Framework为我们提供的Android窗口的具体实现。我们平时调用setContentView()方法设置Activity的用户界面时,实际上就完成了对所关联的PhoneWindow的ViewTree的设置。我们还可以通过Activity类的requestWindowFeature()方法来定制Activity关联PhoneWindow的外观,这个方法实际上做的是把我们所请求的窗口外观特性存储到了PhoneWindow的mFeatures成员中,在窗口绘制阶段生成外观模板时,会根据mFeatures的值绘制特定外观。

3.View绘制的起点

ViewRoot负责执行View绘制的整个流程,每个应用程序窗口的decorView都有一个与之关联的ViewRoot对象,这种关联关系是由WindowManager来维护的,Activity启动时,ActivityThread.handleResumeActivity()方法中建立decorView与ViewRoot的关联。

当建立好了decorView与ViewRoot的关联后,ViewRoot类的requestLayout()方法会被调用,以完成应用程序用户界面的初次布局。实际被调用的是ViewRootImpl类的requestLayout()方法(绘制的起点),源码如下。

 上面的方法中调用了scheduleTraversals()方法来调度一次完成的绘制流程,该方法会向主线程发送一个“遍历”消息,最终会导致ViewRootImpl的performTraversals()方法被调用。

4.ViewRootlmpl

ViewRootImpl 是建立 DecorView 和 Window 之间的联系。

整个View树的绘图流程是在ViewRootImpl类的performTraversals()方法开始的,该函数做的执行过程主要是根据之前设置的状态,判断是否重新计算视图大小(measure)、是否重新放置视图的位置(layout)、以及是否重绘 (draw),其核心也就是通过判断来选择顺序执行这三个方法中的哪个,如下:

这个方法是用来测Root View的。上面传入参数后这个函数走的是MATCH_PARENT,使用MeasureSpec.makeMeasureSpec方法组装一个MeasureSpec,MeasureSpec的specMode等于EXACTLY,specSize等于windowSize,也就是为何根视图总是全屏的原因。

其中的mView就是View对象。如下就是整个流程的大致流程图:

Android中的任何一个布局、任何一个控件都是直接或间接继承自View实现的,当然也包括自定义控件,所以说这些View应该都具有相同的绘制流程与机制才能显示到屏幕上。每一个View的绘制过程都必须经历三个最主要的过程,也就是measure、layout和draw。 

measure: 判断是否需要重新计算View的大小,需要的话则计算;

layout: 判断是否需要重新计算View的位置,需要的话则计算;

draw: 判断是否需要重新绘制View,需要的话则重绘制。

5.View的绘制过程

(1)   measure阶段:目的是计算出控件树中的各个控件要显示其内容的话,需要多大尺寸。起点是ViewRootImpl的measureHierarchy()方法,measureHierarchy()方法中有一段源码如下:

 getRootMeasureSpec()方法用来获取根MeasureSpec,根MeasureSpec代表了对decorView的宽高的约束信息。

先来了解一下MeasureSpec。

MeasureSpec 表示的是一个 32 位的整数值,它的高 2 位表示测量模式 Sp

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值