窗体是视图的容器,视图依赖窗体,手机平台的窗体是PhoneWindow类,它的内部类DecorView是视图树形结构根视图,继承FrameLayout布局。
在Activity的attach方法,创建PhoneWindow,看一下它的构造方法。
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
}
创建一个LayoutInflater布局解析器。在Activity的onCreate方法设置视图布局,这也是初学者最先学习的东西。本文分析一下如何设置视图布局。
初始化布局
我们通常调用setContentView方法设置视图布局,传入参数视图布局资源ID。
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
该方法调用窗体的setContentView方法。将布局资源ID代表的xml文件节点解析成View对象。
private DecorView mDecor;//根View
private ViewGroup mContentParent;//存放解析出外部的View
private ViewGroup mContentRoot;//mDecor的直接子View
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
//初始化mDecor,创建mContentParent和mContentRoot
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
...
} else {
//解析资源ID的View加入到mContentParent的子View中去
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
解析xml、创建DecorView、根据窗体特性初始化特定视图、将视图加到顶层视图中。mContentRoot是DecorView子视图,系统框架在解析时,根据Window不同Feature,选择不同的layoutResource布局资源。
//PhoneWindow的generateLayout方法。mContentRoot创建的代码段。
View in = mLayoutInflater.inflate(layoutResource, null);
//加入顶层视图。
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
在这里,我们选择一种最简单的布局资源文件,screen_simple.xml文件。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme" />
<FrameLayout
android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundInsidePadding="false"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
mContentRoot是screen_simple.xml文件解析出来的视图,将其加入顶层视图。通过findViewById方法解析ID节点获取mContentParent。
资源ID是com.android.internal.R.id.content,类型FrameLayout。
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
一种简单的DecorView视图树形结构图。

利用Layout Inspector工具查看视图层级。

总结
DecorView视图:树形结构顶层视图。
mContentRoot视图:由Android_SDK布局资源文件解析获取。
mContentParent视图:FrameLayout类型,mContentRoot其中一个子视图,装载用户setContentView传入的布局资源。另外,mContentRoot还有其他的子视图,如ActionBar,装载到ViewStub节点。
setContentView方法仅负责视图布局的初始化,实现了树形层级结构,并未对视图实现测量布局和绘制。所以,此方法后,在屏幕上还无法看到视图。
网友评论