重写Android之View的工作原理系列(一)

124 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第二十二天,点击查看活动详情

重写Android之View的工作原理系列(一)

前言

本系列主要介绍两个方面,首先介绍View的工作原理,懂了原理后我们在来实现自定义View。

我们知道在Android中,View是很重要的知识点,我们使用的TextViewImageView等都是继承与View,当然这些都是Android的GUI库提供的基本控件,有时候并不能满足我们的日常开发,我们也需要自定义View,通过自定义View可以实现复杂的一些效果,所以为了我们更好的自定义view,我们需要先了解View的工作原理

ViewRoot和DecorView

我们了解一下几个基本的概念:

  • Activity

Activity只是控制生命周期和处理事件,并不是控制视图显示,真正控制视图的Window。一个Activity包含一个WindowWindow才是真的窗口。

  • Window

Window是视图的承载器,内部持有一个DecorView,这个DecorView才是View的根布局。

Window是一个抽象类,实际在Acitiy中持有的是其子类PhoneWindowPhoneWindow中一个内部类DecorView,通过DecorView来加载Activity中设置的布局。Window 通过WindowManagerDecorView加载其中,并将DecorView交给ViewRoot,进行视图绘制以及其他交互。

  • DecorView

DecorViewFrameLayout的子类,它是Android视图树的根节点视图。DecorView作为顶级View,一般情况下它内部包含一个竖直方向的LinearLayout,在这个LinearLayout里面有上下三个部分,上面是个ViewStub,延迟加载的视图(应该是设置ActionBar,根据Theme设置),中间的是标题栏(根据Theme设置,有的布局没有),下面的是内容栏。我们可以看一下下面的具体布局结构:

381661246970_.pic.jpg

  • ViewRoot

所有View的绘制以及事件分发等交互都是通过它来执行或传递的。ViewRoot对应于ViewRootImlp类,它是链接WindowManagerDecorView的纽带,View的三大流程是通过ViewRoot来完成的。

View的绘制流程是从ViewRootperformTraversals方法开始的,它经过measurelayoutdraw三个过程才能最终将一个View绘制出来,其中measure用来测量View的宽和 高,layout用来确定View在父容器中的放置位置,而draw则负责将View绘制在屏幕上。针对performTraversals的大致流程:

performTraversals.png

如上图所示,performTraversals会依次调用performMeasureperformLayoutperformDraw三个方法,这三个方法分别完成顶级Viewmeasurelayoutdraw这三大流程。其 中在performMeasure中会调用measure方法,在measure方法中又会调用onMeasure方法,在onMeasure方法中则会对所有的子元素进行measure过程,这个时候measure流程就从父容 器传递到子元素中了,这样就完成了一次measure过程。接着子元素会重复父容器的measure过程,如此反复就完成了整个View树的遍历。同理,performLayoutperformDraw的 传递流程和performMeasure是类似的,唯一不同的是,performDraw的传递过程是在draw方法中通过dispatchDraw来实现的,不过这并没有本质区别。

measure过程决定了View的宽/高,Measure完成以后,可以通过getMeasuredWidthgetMeasuredHeight方法来获取到View测量后的宽/高,在几乎所有的情况下它都等同于 View最终的宽/高,但是特殊情况除外,这点在本章后面会进行说明。