安卓View工作流程

目录

一、View基础

1.1View和ViewGroup

1.2 View、Activity、Windows的关系

二、View类简介

三、安卓中的坐标系

四、View的工作流程

4.1 测量(measure)

4.2 布局(layout)

4.3 绘制(draw)

总结


一、View基础

1.1View和ViewGroup

安卓中的View可以理解为屏幕上的一块区域,所有的UI组件(Button、TextView)和布局容器(线性布局、相对布局等)都是View,它们都集成自View类,ViewGroup也是继承于View,因此ViewGroup也可以被当做View使用,至于View和ViewGroup的关系,通常将ViewGroup作为容器来盛装其他组件,而ViewGroup里不仅可以包含普通View组件,还可以再次包含ViewGroup组件,可以由如下图表示:

1.2 View、Activity、Windows的关系

刚接触安卓的时候,我们新建一个空白的Activity,运行一下,就能显示出来UI页面,给人的感觉就像是Activity也是一个界面,其实不然,我们看到的UI页面是通过Activity、windows、View的共同努力才显示出来的。以一个例子来说明三者的关系,我们可以将Activity看做是管理员,将Windows看做显示屏,将View看做显示屏上的信息,三者结合起来就是,管理员控制显示屏显示出了信息,其中,PhoneWindow 是Window的唯一实现,每个 Activity 会创建一个phoneWindow。

在View这一层,又包含了很多层的子View,它们的关系可以用树结构来表示,其中树顶层的View叫DectorView,DecorView 本质上是一个 FrameLayout,它又包含上下两个部分,上面是标题栏,下面是内容栏。在Activity中我们通过setContentView所设置的布局文件其实就是加载到内容栏之中的。

二、View类简介

上面说到,安卓中的View类是各种UI组件/布局的基类,View类共有四个构造方法,如图所示:

它们的使用场景如下:

public View(Context context) {
//如果是通过Java代码new操作符创建的View,则调用这个单参构造函数
}

public View(Context context, @Nullable AttributeSet attrs) {
//如果在通过.xml文件声明的View,则调用第这个双参构造函数
        this(context, attrs, 0);
    }

public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
//View有style属性时调用 }

public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
this(context);
//View有style属性时调用 
}

上面四个构造方法找中,出现了一个参数AttributeSet,中文意思是“属性集”,没错,我们在xml中为View配置的属性就是构造成一个AttributeSet对象传递给View的构造方法,不仅对于系统自带的View可以设置属性,对于自定义View同样可以在xml中配置属性,为了使自定义的View的属性可以在xml中配置,需要以下4个步骤:

1. 通过<declare-styleable>为自定义View添加属性

2. 在xml中为相应的属性声明属性值

3. 在运行时(一般为构造函数)获取属性值

4. 将获取到的属性值应用到View

三、安卓中的坐标系

安卓坐标系与一般的数学坐标系不同,安卓坐标系是以左上角为坐标原点,X轴向右为增大方向,Y轴向下为增大方向:

我们上文中说到,一个页面可能是有很多个View组成的,这些View可能都在不同的位置,一个View的位置是由四个顶点的坐标来决定的,为了便于获取某个点具体的位置,在安卓中,提供了一系列方法,例如下图中的getX、getRawX等,同样地,我们也可以通过getTop、getLeft等方法来获取某个View相对于其父容器的位置,下图较好地表明了这些方法的作用。

此外,额外强调一下在MotionEvent中,get()和getRaw()的区别,get()是触摸点相对于其所在View的坐标系的坐标,而getRaw()是触摸点相对于整个屏幕默认坐标系的坐标,如下图所示:

四、View的工作流程

上文说到,一个页面中可能有很多个View,这些View要想正确地显示出来,必须经过三个过程,分别是测量、布局、绘制。View树中的View自上而下遍历、由父视图到子视图、每一个 ViewGroup 负责测绘它所有的子视图,而最底层的 View 会负责测绘自身。

View的绘制流程开始于:ViewRootImpl对象的performTraversals(),这个方法的核心代码精简如下:


  private void performTraversals() {
        // 1. 执行measure流程
        // 内部会调用performMeasure()
        measureHierarchy(host, lp, res,desiredWindowWidth, desiredWindowHeight);
        // 2. 执行layout流程
        performLayout(lp, mWidth, mHeight);
        // 3. 执行draw流程
        performDraw();
    }

用图表示安卓中View的工作流程,大致如下:

4.1 测量(measure)

测量的过程中,主要是确定各个View的尺寸,系统会先根据xml文件和代码中对不同View属性的设置,根据一定的规则来计算出每个View和ViewGrop的尺寸,并将这些尺寸保存下来。

若是单个View的测量,只需测量自身一个View;若是ViewGroup的测量,需要遍历所有子View的尺寸,根据所有子View的尺寸最终得到ViewGroup父视图的测量结果。过程下图所示:

 4.2 布局(layout)

布局的过程中,主要是根据测量出的结果以及对应的参数,来确定每个View要显示在什么位置,比如View是要居中?左对齐?右对齐?顶部距离多少?左边距离多少?这些问题都是在布局这个过程在明确的。

同样地,如果是单个View的布局,只需要计算这个View自己的位置即可;若是ViewGroup,则需要遍历所有的子View,计算出它们的位置,直到所有的子View在父容器中的位置都已明确,该过程才结束。该过程图示如下:

4.3 绘制(draw)

既然尺寸已经确定,位置也已经固定,那么最后一步就是把View给显示出来了。如果是单个View,把自己的背景、内容、装饰(滚动条等)绘制出来即可;如果是ViewGroup,首先要把ViewGroup的背景和内容绘制出来,然后依旧遍历所有的子View,将子View的背景、内容、装饰(滚动条等)绘制出来,最后绘制ViewGroup的装饰(滚动条等)。其过程如图所示:


总结

本文主要介绍了View的相关基础知识,如有错误还请各位大神指出,由于网络上的大佬们已经给出了详细的图示,本文部分图示直接引用自网络,如有侵权请联系删除,谢谢!同时也欢迎各位大佬来讨论和交流技术,本人邮箱hbutys@vip.qq.com

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值