1. 程式人生 > >Window窗口布局 --- DecorView淺析

Window窗口布局 --- DecorView淺析

開發中,通常都是在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結構,可以看到結構如下:

相關推薦

Window --- DecorView淺析

開發中,通常都是在onCreate()中呼叫setContentView(R.layout.custom_layout)來實現想要的頁面佈局,我們知道,頁面都是依附在視窗之上的,而DecorView即是視窗最頂層的檢視。Android frameworks中,與視窗檢視處理相關的類,主要是Window及其實現

05 用xml檔案視覺化設計

前面一直用程式碼來設計視窗的佈局,每次修改後,只有程式執行時才可看到設計的結果,而且當視窗的控制元件較多時,寫程式碼的方式較為麻煩了。 所以Android裡還提供了用xml檔案,用視覺化的方式來設計窗口布局. 首先還是先用嚮導建立一個”Add No Act

VC6 恢復

vc 6.0中的小控制元件不小心點沒有,右鍵下圖中紅筆圈中的地方,勾選相應的控制元件就好了。 如果workspace視窗不能鎖定在視窗的左側時可以試試下面的這個命令。 vc 6.0中有do

Qt實戰--主

QMainWindow MainWindow類我們一般選擇直接繼承自QMainWindow,因為QMainWindow已經向我們提供了一個常用的應用程式主窗口布局,包括QMenuBar選單欄、QToolBar工具欄、QStatusBar狀態列、QDo

QT5(5)

程式碼自行補充標頭檔案 一、分割視窗QSplitter 在新建專案時不選建立視窗,在main.cpp中修改為: #include "mainwindow.h" #include <QApplication> #include <QSp

vs2012恢復

我的環境。WIN7系統,使用的VS2012 問題出現在系統藍屏後,VS2012窗口布局出現問題,並不是我以前的佈局,點選視窗選單選擇重置窗口布局也不起作用。 解決方法:點選工具選單--匯入和匯出設定 有3個選項 。匯入,匯出,和重置。 選擇重置,VS2012會儲存你當前的配

Qt Creator

    使用Qt Creator對視窗進行佈局,相對於使用C++程式碼佈局而言,直觀快速,是首選的方法。本文重點在於敘述使用Qt Creator對視窗進行佈局的一些技巧。 1 Layouts     在Qt Creator左側的控制元件列表中,有4種佈局控制元件,而在其上方

pyqt4 基本視窗,,設定logo,視窗最大最小化

#-*- coding:utf-8 -*- ####上面一行是指定編碼,這樣檔案中(包括註釋)才能使用中文,否則無法執行 #pyqt4基本視窗示例 from PyQt4.QtCore import * from PyQt4.QtGui import * import sys

MATLAB之simulink與command window交互

image simulink http sim log 技術分享 logs blog cnblogs simulink中scope數據傳輸到command window窗口中 再完善!!!MATLAB之simulink與command window窗口交互

emWin 2天速成實例教程003_Framewin和Window控件和2D繪圖

emwin framewin window 控件 窗體 備註:(1)打開工程目錄下的"Exe\GUISimulationDebug.exe"即可看到效果。(2)看完教程000~005就基本會用emWin做項目,其他章節可以需要時再參考。(1) emWin的每個界面都需要

javascript獲取window常用函數

javascript獲取window窗口獲取窗口滾動條高度: /******************** *獲取窗口滾動條高度 ******************/ function getScrollTop() { var scrollTop=0; if(document.documentElement&

通過C# WinForm控件創建的WPF WIndow控件無法輸入的問題

一次 開始 info keyboard 輸入法 .dll enable board 非模態 原文:通過WinForm控件創建的WPF 控件無法輸入的問題 今天把寫的一個WPF程序發布到別的機器上執行,發現一個比較奇怪的問題:在那個機器上用英文輸入法無法輸入數字,非要切換到

Window

遊戲 pri iou console 技術分享 window hiera 服務 兼容 Window 窗口 Next Window:下一個窗口 Previous Window:前一個窗口 Layouts:布局 Unity Services:統一的服務 Scene:場景 Ga

恢復VS2013的默認

href jpg index -o tex f2c http wrap self 打開VS2013 在菜單欄中找到“Window”即“窗口”選項

QMdiArea及QMdiSubWindow實現父子方法

light reat htm god cti www 圖片 des tac 版權聲明:若無來源註明,Techie亮博客文章均為原創。 轉載請以鏈接形式標明本文標題和地址: 本文標題:QMdiArea及QMdiSubWindow實現父子窗口及布局方法 本文地址:ht

Win32API全類的註冊與創建

zcl icon 全局 class border 字符 rbac 標題 def Win32API全局窗口類的註冊 應用程序全局窗口類的註冊 typedef struct tagWNDCLASSEX { UINT cbSize; //

洛谷P1886 滑動(POJ.2823 Sliding Window)(區間最值)

最大 ide dma include names target org void blog To 洛谷.1886 滑動窗口 To POJ.2823 Sliding Window 題目描述 現在有一堆數字共N個數字(N<=10^6),以及一個大小為k的窗口。現在這個

關於window.open的resize事件

ren enter itl 窗口 query 參考手冊 cti cnblogs span jQuery 事件 - resize() 方法 當調整瀏覽器窗口的大小時,發生 resize 事件。 resize() 方法觸發 resize 事件,或規定當發生 resize 事件時

[Leetcode] minimum window substring 最小字符

為什麽 目的 -s pan 遍歷 uno 一個 tro you Given a string S and a string T, find the minimum window in S which will contain all the characters in T

WPF window反饋效果(拉動/漸變)

nbsp Owner oar == boa ado 每次 value cti 當子窗口顯示後,點擊子窗口外部,需要有反饋動畫。 實現: 1.事件捕捉 每次點擊子窗口外部,即母窗口時,事件捕捉如下 HwndSource hwndSource = PresentationSo