开发中,通常都是在onCreate()中调用setContentView(R.layout.custom_layout)来实现想要的页面布局,我们知道,页面都是依附在窗口之上的,而DecorView即是窗口最顶层的视图。Android frameworks中,与窗口视图处理相关的类,主要是Window及其实现类PhoneWindow

public class PhoneWindow extends Window implements MenuBuilder.Callback {
  
  //...   //窗口顶层View
private DecorView mDecor;

  //所有自定义View的根View, id="@android:id/content"
private ViewGroup mContentParent;

DecorView其实是PhoneWindow中的一个内部类,本质上也是一个View,其只是扩展了FrameLayout的实现

private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {

    //...

页面layout被添加至窗口Window的流程大致如下:

1,Activity中调用setContentView(R.layout.custom_layout), 具体实现为PhoneWindow中的同名方法

 public void setContentView(int layoutResID) {
  
  //getWindow()获取的即是PhoneWindow对象
  getWindow().setContentView(layoutResID);
}

2, PhoneWindow执行setContentView(int layoutResource)

public void setContentView(int layoutResID) {
  //初始,mContentParent为空
  if (mContentParent == null) {
    installDecor();
  } else {
    mContentParent.removeAllViews();
  }
  //inflate自定义layout, 并将mContentParent作为其根视图
  mLayoutInflater.inflate(layoutResID, mContentParent);

3, PhoneWindow.installDecor()

 private void installDecor() {
  if (mDecor == null) {
     //new一个DecorView
    mDecor = generateDecor();
    mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
    mDecor.setIsRootNamespace(true);
    if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
      mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
    }
  }
  if (mContentParent == null) {
     //这一步会设置窗口的修饰文件,并将id为ID_ANDROID_CONTENT的view find出来作为返回值赋值给mContentParent
    mContentParent = generateLayout(mDecor);

4, PhoneWindow.generateLayout(DecorView decor)

protected ViewGroup generateLayout(DecorView decor) {
  //4.1,获取<Application android:theme=""/>, <Activity/>节点指定的themes或者代码requestWindowFeature()中指定的Features, 并设置
  TypedArray a = getWindowStyle();
  //...
  
  //4.2,获取窗口Features, 设置相应的修饰布局文件,这些xml文件位于frameworks/base/core/res/res/layout下
  int layoutResource;
  int features = getLocalFeatures();
  if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
    if (mIsFloating) {
      TypedValue res = new TypedValue();
      getContext().getTheme().resolveAttribute(com.android.internal.R.attr.dialogTitleIconsDecorLayout, res, true);
      layoutResource = res.resourceId;
    } else {
  layoutResource = com.android.internal.R.layout.screen_title_icons;
  }
  removeFeature(FEATURE_ACTION_BAR);
  } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0 && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
  layoutResource = com.android.internal.R.layout.screen_progress;
  //...
  
  mDecor.startChanging();
  //4.3, 将上面选定的布局文件inflate为View树,添加到decorView中
  View in = mLayoutInflater.inflate(layoutResource, null);
  decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
  //将窗口修饰布局文件中id="@android:id/content"的View赋值给mContentParent, 后续自定义的view/layout都将是其子View
  ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
  if (contentParent == null) {
    throw new RuntimeException("Window couldn't find content container view");
  }
  //...

从上述步骤中,可以看出为什么在代码中必须要在setContentView(...)之前才能执行requestWindowFeature(...)

5, 最后页面中设置的自定义layout会被添加到mContentParent中

mLayoutInflater.inflate(layoutResID, mContentParent);

所以,Window窗口的布局层次结构(features不同,可能标题栏不存在, 这种情况下,窗口修饰视图区域与mContentParent内容区域重叠)如下所示:

示例:

Activity代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
  //设置窗口无标题栏
  requestWindowFeature(Window.FEATURE_NO_TITLE);
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_decor);
}

activity_decor.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".DecorActivity"> <TextView
android:text="@string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content" /> <TextView
android:text="@string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/> </RelativeLayout>
onCreate()中设置的Window.FEATURE_NO_TITLE对应的窗口修饰布局文件为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" />
<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>
源码中id为"@android:id/content"的FrameLayout就是内容区域,在整个流程中,其会赋值给PhoneWindow类中的属性mContentParent, 运行应用后,使用SDK提供的hierarchyviewer工具查看页面的ViewTree结构,可以看到结构如下:

参考资料:
http://blog.csdn.net/qinjuning/article/details/7226787
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.2_r1/android/view/Window.java?av=f
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.2_r1/com/android/internal/policy/impl/PhoneWindow.java?av=f
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.2_r1/frameworks/base/core/res/res/layout/screen_simple.xml?av=f
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.2_r1/android/app/Activity.java?av=f
 

Window窗口布局 --- DecorView浅析的更多相关文章

  1. [转载]ExtJs4 笔记(9) Ext.Panel 面板控件、 Ext.window.Window 窗口控件、 Ext.container.Viewport 布局控件

    作者:李盼(Lipan)出处:[Lipan] (http://www.cnblogs.com/lipan/)版权声明:本文的版权归作者与博客园共有.转载时须注明本文的详细链接,否则作者将保留追究其法律 ...

  2. ExtJs4 笔记(9) Ext.Panel 面板控件、 Ext.window.Window 窗口控件、 Ext.container.Viewport 布局控件

    本篇讲解三个容器类控件. 一.面板控件 Ext.Panel 一个面板控件包括几个部分,有标题栏.工具栏.正文.按钮区.标题栏位于最上面,工具栏可以在四个位置放置,围绕中间部分正文,按钮区位于最小方.下 ...

  3. 窗口-EasyUI Window 窗口、EasyUI Dialog 对话框、EasyUI Messager 消息框

    EasyUI Window 窗口 扩展自 $.fn.panel.defaults.通过 $.fn.window.defaults 重写默认的 defaults. 窗口(window)是一个浮动的.可拖 ...

  4. (四)EasyUI 使用——form表单2 & window窗口

    form表单组件主要有以下内容(如下图)      6. progressbar进度条  每隔1秒让进度条按随机数填充,直至充满进度条刻度(只能执行一次) 进度条: <div id=" ...

  5. 第二百零三节,jQuery EasyUI,Window(窗口)组件

    jQuery EasyUI,Window(窗口)组件 学习要点: 1.加载方式 2.属性列表 3.事件列表 4.方法列表 本节课重点了解 EasyUI 中 Window(窗口)组件的使用方法,这个组件 ...

  6. 保持plsql窗口布局

    在window菜单中有个 save layout 项,设置好窗口布局后,选一下此项就保存你当前的窗口布局了,下次启动就不用再设置了.

  7. EasyUI笔记(三)Window窗口

    本系列只列出一些常用的属性.事件或方法,具体完整知识请查看API文档 Window(窗口) 窗口控件是一个浮动和可拖拽的面板可以用作应用程序窗口.默认情况下,窗口可以移动,调整大小和关闭.它的内容也可 ...

  8. IDEA的窗口布局设置

    修改idea的窗口布局 idea默认的窗口模式是如: 可以通过File->Appearance->Window Options->勾选 Widescreen tool window ...

  9. JavaScript:window窗口对象

    在JavaScript中,window表示的就是一个窗口对象.所以在整个处理过程之中,所有的操作都是以弹框为主 的.范例1:使用警告框 <script type="text/javas ...

随机推荐

  1. Grid控件

    Grid控件是WPF布局容器中功能最强大.最灵活的控件.Grid控件基本上能够完成其他WPF容器控件所能完成的功能,Microsoft建议大多数界面的布局都使用Grid控件来实现,因此默认情况下.vs ...

  2. C# 随机数类

    using System; namespace DotNet.Utilities { /// <summary> /// BaseRandom /// 产生随机数 /// /// 随机数管 ...

  3. java web工程web.xml介绍

    转载自:http://blog.csdn.net/believejava/article/details/43229361 Web.xml详解: 1.web.xml加载过程(步骤) 首先简单讲一下,w ...

  4. js中获取css样式的两种方式

    1. 对象.style.样式名  弊端就是只能获取行内样式 2.window.getComputedStyle(对象,null); 最好用第二种方式 <!DOCTYPE html> < ...

  5. csharp:A Custom CheckedListBox with Datasource

    /// <summary> /// (eraghi) /// Custom CheckedListBox with binding facilities (Value property) ...

  6. Bzoj2395: [Balkan 2011]Timeismoney(最小乘积生成树)

    问题描述 每条边两个权值 \(x,y\),求一棵 \((\sum x) \times (\sum y)\) 最小的生成树 Sol 把每一棵生成树的权值 \(\sum x\) 和 \(\sum y\) ...

  7. JavaScript函数与面向对象

    一.JS面向对象 function Func(name,age){ //this = obj this.Name = name; this.Age = age; } obj = new Func('r ...

  8. ListView中Item与Checkable子类控件抢焦点问题

    Android开发中,经常需要为ListView定制Adapter,绑定各种子类控件.如果Item包含Button等Checkable的控件,那么就会发生点击Item无法响应的问题.原因是自己定义的I ...

  9. ls 操作命令 -l/-R和rm -r dir 功能实现

    ls -R #include <sys/stat.h> #include <dirent.h> #include <fcntl.h> #include <st ...

  10. 机器学习入门KNN近邻算法(一)

    1 机器学习处理流程: 2 机器学习分类: 有监督学习 主要用于决策支持,它利用有标识的历史数据进行训练,以实现对新数据的表示的预测 1 分类 分类计数预测的数据对象是离散的.如短信是否为垃圾短信,用 ...