【Android】之【View绘制】

时间:2021-04-08 01:14:57

一、View绘制基本流程

简单的可以说,如 measure,layout,draw 分别对应测量,布局,绘制三个过程。

  • ① measure:测量。系统会先根据xml布局文件和代码中对控件属性的设置,来获取或者计算出每个View和ViewGrop的尺寸,并将这些尺寸保存下来。
  • ② layout:布局。根据测量出的结果以及对应的参数,来确定每一个控件应该显示的位置。
  • ③ draw:绘制。确定好位置后,就将这些控件绘制到屏幕上。

总体流程来说Android 的绘制基本可以分为

  • ①* View 的绘制 --> 也就是​​ViewrootImpl​​​,在这姑且先将它理解为​​Activity​​
  • ② Viewgroup的绘制
  • ③ View 的绘制

自定义View的时候一般需要重写父类的onMeasure()、onLayout()、onDraw()三个方法,来完成视图的展示过程。

二、Android视图层次结构简介

【Android】之【View绘制】

Activity内部有个Window成员,它的实例为PhoneWindow,PhoneWindow有个内部类是DecorView,这个DecorView就是存放布局文件的,里面有TitleActionBar和我们setContentView传入进去的layout布局文件

Window类:是一个抽象类,提供绘制窗口的API。
PhoneWindow:是继承Window的一个具体的类,该类内部包含了一个DecorView对象,该DectorView对象是所有应用窗口(Activity界面)的根View。
DecorView:继承FrameLayout,里面id=content的就是我们传入的布局视图,它可以被认为是 ​​Android​​ 视图树的根节点视图。

【Android】之【View绘制】

AndroidStudio工具中提供了一个布局视察器工具,通过Tools > Android > Layout> Inspector可以查看具体某个Activity的布局情况。上图中,左边树状结构对应了右边的可视图,可见DecorView是整个界面的根视图,对应右边的红色框,是整个屏幕的大小。黄色边框为状态栏部分;那个绿色边框中有两个部分,一个是白框中的ActionBar,对应了上图中紫色部分的TitleActionBar部分,即标题栏,平时咱们可以在Activity中将其隐藏掉;另外一个蓝色边框部分,对应上图中最里面的蓝色部分,即ContentView部分。下图中左边有两个蓝色框,上面那个中有个“contain_layout”,这个就是Activity中setContentView中设置的layout.xml布局文件中的最外层父布局,咱们能通过layout布局文件直接完全操控的也就是这一块,当其被add到视图系统中时,会被系统裹上ContentFrameLayout(显然是FrameLayout的子类),这也就是为什么添加layout.xml视图的方法叫setContentView(…)而不叫setView(…)的原因。

三、相关问题点

1、什么是 Activity?从视图角度分析

  • ​​Activity​​​ 并不负责视图控制,它只是控制生命周期和处理事件。真正控制视图的是​​Window​​​。一个​​Activity​​​ 包含了一个​​Window​​​,​​Window​​才是真正代表一个窗口。
  • Activity​​​就像一个控制器,统筹视图的添加与显示,以及通过其他回调方法,来与​​Window​​​、以及​​View​​ 进行交互。

2、什么是Window?

  • ​​Window​​​ 是一个抽象类,实际在​​Activity​​​中持有的是其子类​​PhoneWindow​​​。​​PhoneWindow​​​中有个内部类​​DecorView​​​,通过创建​​DecorView​​​ 来加载​​Activity​​​中设置的布局​​R.layout.activity_main​​

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

  • Window​​​ 通过​​WindowManager​​​ 将​​DecorView​​​ 加载其中,并将​​DecorView​​​ 交给​​ViewRootimpl​​,进行视图绘制以及其他交互

3、什么是DecorView?

  • ​​DecorView​​​ 是 ​​FrameLayout​​​ 的子类,它可以被认为是 ​​Android​​ 视图树的根节点视图。

  • ​​DecorView​​​ 作为* ​​View​​,一般情况下它内部包含一个竖直方向的 ​​LinearLayout​​,在这个 ​​LinearLayout​​ 里面有上下三个部分,上面是个 ​​ViewStub​​,延迟加载的视图(应该是设置​​ActionBar​​,根据 ​​Theme​​ 设置),中间的是标题栏(根据Theme设置,有的布局没有),下面的是内容栏。具体情况和Android版本及主体有关。

  • ​​在 ​​Activity​​​ 中通过 ​​setContentView​​​ 所设置的布局文件其实就是被加到内容栏之中的,成为其唯一子 ​​View​​​,就是上面的 ​​id​​​ 为 ​​content​​​ 的 ​​FrameLayout​​​ 中,在代码中可以通过 ​​content​​ 来得到对应加载的布局。

4、什么是 ViewRootImpl

从结构上来看,​​ViewRootImpl​​​ 和 ​​ViewGroup​​ 其实是一种东西。

相同点

  • 它们都继承了​​ViewParent​​。
  • ViewParent​​​ 是一个接口,定义了一些父​​View​​​ 的基本行为,比如​​requestlayout​​​,​​getparent​​ 等。

不同点

  • ViewRootImpl​​​ 并不会像​​ViewGroup​​ 一样被真正绘制在屏幕上
  • 在​​Activity​​​ 中,它是专门用来绘制​​DecorView​​​ 的,核心方法是​​setView​​
    【Android】之【View绘制】

5、Activity,window,View 三者之间的关系是什么?

​​window​​​ 是 ​​activity​​​ 的一个成员变量,​​window​​​ 和 ​​View​​ 是“显示器”和“显示内容”的关系

  • Window 抽象类,PhoneWindow 唯一实现类,用于加载​​Activity​​​ 的*​​View​​​ –​​DecorView​​

  • 一个 Activity 对应一个 Window 也就是 PhoneWindow,一个 PhoneWindow 持有一个 DecorView 的实例,DecorView 本身是一个 FrameLayout

6、Activity、PhoneWindow、DecorView 关系图

类似的问题,其实问的基本是一个东西。activity​​​ 的 ​​setContentView​​​ 方法实际上是就是交给 ​​phonewindow​​​ 去做的。​​window​​​ 和 ​​View​​ 的关系可以类比为显示器和显示的内容。
【Android】之【View绘制】

7、Android 中 xml 布局怎么显示到屏幕上的?

  • 在整个 ​​Activity​​​ 的生命周期中,​​setContentView​​​ 是在 ​​onCreate​​​ 中调用的,它实现了对资源文件的解析,完成了 ​​xml​​​ 文件到 ​​View​​ 的转化。

  • 那么 View 真正开始绘制是在哪个生命周期呢?
    答案是 ​​onResume​​ 结束后

  • onResume​​​ 之后,从 Activity 中的 Window 实例中获取​​Decorview​​。
    调用​​activity​​​ 中​​windowmanager​​​ 的​​addView​​​ 方法,将​​decorView​​​ 传入到​​ViewRootImpl​​​ 的​​setView​​ 方法中通过​​ViewRootImpl.setView()​​​ 来完成​​View​​ 的绘制

四、参考