一. 前言

在学习自定义View之前,我们首先需要了解View是怎么被一步步显示出来的。为此,我们需要了解 ViewRoot,DecorView,Window,Activity。

二. ViewRoot

1. 作用

连接器,连接 WindowManager 和 DecorView,完成 View 的绘制流程。

2. 具体描述

① ViewRoot是抽象类,ViewRootImpl是实现类。

② 与 WindowManagerService 通讯,调整窗口大小以及布局。

③ 向 DecorView 派发输事件。

④ 完成三大绘制流程:measure,layout,draw。

三. DecorView

1. 定义

顶层View,即 Android 视图树的根节点;同时也是 FrameLayout 的子类。

2. 作用

① 加载,显示布局。

② View层的事件都先经过 DecorView,再传递到 View。

3. 特别说明

DecorView内含1个竖直方向的LinearLayout,分为2部分:上 = 标题栏(titlebar)和 下 = 内容栏(content)

Activity中通过 setContentView()所设置的布局文件其实是被加到内容栏之中的,成为其唯一子View(id为content的FrameLayout)。

所以我们可以在代码中获取设置的布局:

1
2
3
4
5
// 1. 得到content
ViewGroup content = (ViewGroup)findViewById(android.R.id.content);

// 2. 得到设置的View
ViewGroup rootView = (ViewGroup) content.getChildAt(0);

四. Window

1. 作用

承载器,承载着 View 的显示。

2. 具体描述

① Window类是抽象类,PhoneWindow类是实现类。

② PhoneWindow类会创建其内部类DecorView,来加载Activity中设置的布局。

③ PhoneWindow类加载布局后还需要显示,在显示的时候会获取 WindowManager 将 DecorView 传入其中。

⑤ WindowManager 内部创建了一个 ViewRootImpl 对象,负责绘制各个子View,处理事件。

五. Activity

1. 作用

控制器,控制生命周期,处理事件。

2. 特别注意

一个Activity包含一个Window,Activity不负责视图的控制,真正负责视图控制的是Window。

六. 总结

1. 创建DecorView的过程

Activity首先在Attach方法中生成了PhoneWindow的实例,然后在setContentView中直接交给Window来装载视图。先在PhoneWindow中创建了一个DecroView,其中创建的过程中可能根据Theme不同,加载不同的布局格式,例如有没有ActionBar等,然后再向content中加入子View,即Activity中设置的布局。

2. 显示DecorView的过程

当我们执行了Activity.makeVisible()方法之后,界面才对我们是可见的。wm.addView起到了重要的作用,因为其内部创建了一个ViewRootImpl对象,负责绘制显示各个子View。

1
2
3
4
5
6
7
8
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());//将DecorView添加到WindowManager
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);//DecorView可见
}

详细内容参考:自定义View-DecorView创建&显示

参考文章

Android自定义View基础:ViewRoot、DecorView & Window的简介

Activity、Window、DecorView与ViewRoot之间的关系