分析Android的View树
我们知道每一个Activity都包含一个Window窗口,在Android studio 中,通过双击Shift键,找到Window,然后单击它,我们去看一下Window的源码:
在AS中找源码
Window
/**
* Abstract base class for a top-level window look and behavior policy. An
* instance of this class should be used as the top-level view added to the
* window manager. It provides standard UI policies such as a background, title
* area, default key processing, etc.
*
* <p>The only existing implementation of this abstract class is
* android.view.PhoneWindow, which you should instantiate when needing a
* Window.
*/
public abstract class Window {
...
}
首先我们看到Window是一个抽象类,谷歌工程师在注释中解释的很清楚了:
An instance of this class should be used as the top-level view added to the window manager,It provides standard UI policies such as a background, title area, default key processing, etc
:
一个此类的实例必须作为window manager的顶级view,它提供了比如:背景、标题等等。。
The only existing implementation of this abstract class is android.view.PhoneWindow, which you should instantiate when needing a Window:
此抽象类的唯一一个实现类是PhoneWindow,当你需要一个窗口时,应该实例化
PhoneWindow
public class PhoneWindow extends Window implements MenuBuilder.Callback {
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
ViewGroup mContentParent;
}
可以看到DecorView是作为window的顶级的view,而ViewGroup用来放置视图的内容,它有可能是DecorView本身也有可能是DecorView所包含的子内容(这里有点不太懂。。)
看看DecorView
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
...
private View mFloatingActionModeOriginatingView;
// View added at runtime to draw under the status bar area
private View mStatusGuard;
// View added at runtime to draw under the navigation bar area
private View mNavigationGuard;
...
}
DecorView继承自FrameLayout
,我们那些ActionBar,ContentView都包含在这里面
mStatusGuard:在运行时候绘制在状态栏下
mNavigationGuard:在运行时候绘制在导航栏下
mFloatingActionModeOriginatingView:另外一个包含的view (?)
至此,我们可以得出外层的view嵌套关系如下:
窗口
DecorView中的view具体是怎么样的呢?我们可以先建一个HelloWorld工程,通过AS自带的Layout Inspector来分析层级,具体打开:Tools--->Android--->Layout Inspector
HelloWorld
我们可以看到DecorView下居然有三个子view,通过右边的尺寸可以得到
DecorView的height为:1920(说明实验机器为1920x1080的)
linearLayout的height为:1812
navigationBarBackground的height为:108
statusBarBackground的height为:72
通过小学数据可以得到:1920=1812+108,
再通过点击每个子view,可以发现,statusBarBackground应该包含在linearLayout中,所以结构图对应如下:
DecorView的子view
再接着看LinearLayout的子view:
image.png
为什么会有一个ViewStub 和一个LinearLayout呢?
通过查询PhoneWindow 中设置布局的代码
protected ViewGroup generateLayout(DecorView decor) {
...
int features = getLocalFeatures();
//一系列的if else,根据用户设置的主题去加载不同的布局
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
...
}
else if(..){
...
}else{
// Embedded, so no decoration is needed.
layoutResource = R.layout.screen_simple;
// System.out.println("Simple!");
}
}
找到了关键的R.layout.screen_simple,也就是我们上面看到的那个布局,这就是为什么我们要在setContentView前面调用requesetFeature的原因。
FrameLayout只有一个子布局:ActionBarOverlayLayout,下面有一个content,里面包含的就是我们最熟悉的xml布局了,另一个子view是ActionBarContainer就是我们的ActionBar了
总结一下:
- Window是一个抽象类,里面含有背景,标题等的一些方法,而PhoneWindow是Window的唯一的实现类,通过DecorView来添加顶级视图
- Activity中的Window通过getWindow获取
- 我们在setContentView的xml布局体现在@id/content里