Window
该类是一个抽象类,提供了绘制窗口的一组通用API。
PhoneWindow
该类继承于Window类,是Window类的具体实现,即我们可以通过该类具体去绘制窗口。并且,该类内部包含了 一个DecorView对象,该DectorView对象是所有应用窗口(Activity界面)的根View。
DecorView
该类是一个FrameLayout的子类,并且是PhoneWindow的内部变量,该类就是对普通的FrameLayout进行功能的扩展,更确切点可以说是修饰(Decor的英文全称是Decoration,即“修饰”的意思),比如说添加TitleBar(标题栏),以及TitleBar上的滚动条等 。最重要的一点是,它是所有应用窗口的根View 。
包含ContentView和其他(StatusBar,ActionBar、ToolBar等)
ContentView
真正包含我们写的Layout的父布局,是DecorView的一个子类,可以通过findViewById(com.android.internal.R.id.content)拿到该对象。
生成ContentView的源码参考
//generateLayout
protected ViewGroup generateLayout(DecorView decor) {
...
int layoutResource;
int features = getLocalFeatures();
// System.out.println("Features: 0x" + Integer.toHexString(features));
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
layoutResource = R.layout.screen_swipe_dismiss;
} else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleIconsDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_title_icons;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
// System.out.println("Title Icons!");
} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {
// Special case for a window with only a progress bar (and title).
// XXX Need to have a no-title version of embedded windows.
layoutResource = R.layout.screen_progress;
// System.out.println("Progress!");
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
// Special case for a window with a custom title.
// If the window is floating, we need a dialog layout
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogCustomTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_custom_title;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
// If no other features and not embedded, only need a title.
// If the window is floating, we need a dialog layout
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
layoutResource = a.getResourceId(
R.styleable.Window_windowActionBarFullscreenDecorLayout,
R.layout.screen_action_bar);
} else {
layoutResource = R.layout.screen_title;
}
// System.out.println("Title!");
} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
layoutResource = R.layout.screen_simple_overlay_action_mode;
} else {
// Embedded, so no decoration is needed.
layoutResource = R.layout.screen_simple;
// System.out.println("Simple!");
}
mDecor.startChanging();
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
//ID_ANDROID_CONTENT = com.android.internal.R.id.conten
...
}
通过源码会发现会根据设置主题的不同,ContentView的具体实现layout会不一样!举例说明screen_action_bar.xml(有actionBar)和screen_custom_title.xml(无actionBar)
- screen_action_bar.xml
<com.android.internal.widget.ActionBarOverlayLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/decor_content_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:splitMotionEvents="false"
android:theme="?attr/actionBarTheme">
<FrameLayout android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.android.internal.widget.ActionBarContainer
android:id="@+id/action_bar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
style="?attr/actionBarStyle"
android:transitionName="android:action_bar"
android:touchscreenBlocksFocus="true"
android:gravity="top">
<com.android.internal.widget.ActionBarView
android:id="@+id/action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?attr/actionBarStyle" />
<com.android.internal.widget.ActionBarContextView
android:id="@+id/action_context_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
style="?attr/actionModeStyle" />
</com.android.internal.widget.ActionBarContainer>
<com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?attr/actionBarSplitStyle"
android:visibility="gone"
android:touchscreenBlocksFocus="true"
android:gravity="center"/>
</com.android.internal.widget.ActionBarOverlayLayout>
- screen_custom_title.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:fitsSystemWindows="true">
<!-- Popout bar for action modes -->
<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/title_container"
android:layout_width="match_parent"
android:layout_height="?android:attr/windowTitleSize"
android:transitionName="android:title"
style="?android:attr/windowTitleBackgroundStyle">
</FrameLayout>
<FrameLayout android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
setContentView()
Activity的setContetnView()最后会调用PhoneWindow的setContentView();
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
//如已经存在,会将之前的View都全部移除掉,所以setContentView可以反复调用
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
...
}
DectorView是在首次setContentView的时候才进行初始化的
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
}
...
}