Andriod中Style/Theme原理以及Activity界面文件選取過程淺析

 

      經過對前面的一篇博文<從setContentView()談起>的學習,咱們掌握了Activity組件佈局文件地建立過程以及java

 其頂層控件DecorView,今天咱們繼續庖丁解牛---深刻到其中的generateLayout()方法,步步爲營掌握一下內容:android

         一、Activity中Theme(主題)的系統定義以及使用之處;app

         二、如何根據設置的Feature(屬性)選擇合適的佈局文件。框架

 

 另外,對於下文中Theme和Style的概念進行一個簡要說明:ide

      都是由<style />節點進行定義的。但應用在<application />和<activity />則爲theme,應用在<View />則爲style.函數

 

1、關於Theme主題的使用方法以及原理分析

 

    一般來講,能夠直接使用系統定義好的Style/Theme,畢竟,系統爲咱們提供了豐富地選擇。固然,你也能夠oop

 自定義Theme,前提是該Theme必須繼承與某個已經存在地Theme,不然編譯器會提示錯誤的。源碼分析

  一、 應用Theme屬性兩種方式

      ①、在AndroidManifest.xml文件中在<application/>或者<activity />節點設置android:theme屬性.佈局

      ②、直接在代碼中調用方法setTheme()設置該Activity的主題,必須得在第一次調用setContentView()前設置,學習

  不然,也是沒有效果的(具體緣由可見後面分析)。

 

  二、原理分析

      Android的全部系統資源定義位置存放在 frameworks\base\core\res\ 路徑下,編譯時會造成apk文件,即

 framework-res.apk,全部應用程序共享。

     實際上任何Style/Theme也是一組自定義屬性集合,其內置在Android系統資源中,以下所示:

            文件路徑:frameworks\base\core\res\res\values\attrs.xml

 

[java]  view plain copy print ?
  1. <!-- The set of attributes that describe a Windows's theme. -->  
  2.   <declare-styleable name="Window">  
  3.       <!-- 常見的Window屬性  -->  
  4.         
  5.       <attr name="windowBackground" />        //該界面所對應的背景圖片, drawable / color  
  6.       <attr name="windowFrame" />             //該界面所對應的前景frontground圖片, drawable / color  
  7.       <attr name="windowNoTitle" />           //是否帶有title , boolean類型        
  8.       <attr name="windowFullscreen" />        //是否全屏  ,  boolean類型        
  9.       <attr name="windowIsFloating" />        //是不是懸浮窗類型 , boolean類型       
  10.       <attr name="windowIsTranslucent" />     //是否透明 , boolean類型       
  11.       <attr name="windowSoftInputMode" />     //設置鍵盤彈出來的樣式 , 例如: adjustsize 等 ,其實也是int類型  
  12.         
  13.       <!-- more 更多不常見地Window屬性-->  
  14.       ...  
  15.       
  16.   </declare-styleable>  

      特殊的是若是某個自定義屬性若是沒有指名 format屬性,那麼該屬性必須在當前已經定義,即該屬性只是一個

  別名。

      大部分Android屬性定義在 name = "Theme"的屬性集合下(僅列出Window attrs):   

          文件路徑:frameworks\base\core\res\res\values\attrs.xml

[java]  view plain copy print ?
  1. <!-- These are the standard attributes that make up a complete theme. -->  
  2. <declare-styleable name="Theme">  
  3.     <!-- Drawable to use as the overall window background.  There are a  
  4.          few special considerations you should use when settings this  
  5.          drawable:  
  6.     -->  
  7.     <attr name="windowBackground" format="reference" />  
  8.     <!-- Drawable to use as a frame around the window. -->  
  9.     <attr name="windowFrame" format="reference" />  
  10.     <!-- Flag indicating whether there should be no title on this window. -->  
  11.     <attr name="windowNoTitle" format="boolean" />  
  12.     <!-- Flag indicating whether this window should fill the entire screen. -->  
  13.     <attr name="windowFullscreen" format="boolean" />  
  14.     <!-- Flag indicating whether this is a floating window. -->  
  15.     <attr name="windowIsFloating" format="boolean" />  
  16.     <!-- Flag indicating whether this is a translucent window. -->  
  17.     <attr name="windowIsTranslucent" format="boolean" />  
  18.     <!-- Flag indicating that this window's background should be the  
  19.          user's current wallpaper. -->  
  20.     <attr name="windowShowWallpaper" format="boolean" />  
  21.     <!-- This Drawable is overlaid over the foreground of the Window's content area, usually  
  22.          to place a shadow below the title.  -->  
  23.     <!-- This Drawable is overlaid over the foreground of the Window's content area, usually  
  24.          to place a shadow below the title.  -->  
  25.     <attr name="windowContentOverlay" format="reference" />      
  26.     <!--more -->       
  27.  </declare-styleable>  
   

 

     屬性定義如上,Android系統中這些屬性定義了不少Style/Theme ,常見的有以下 :

[java]  view plain copy print ?
  1. android:theme="Theme"            //默認地Theme  
  2. android:theme="Theme.Light"      //背景爲白色    
  3. android:theme="Theme.Light.NoTitleBar"              //白色背景並沒有標題欄     
  4. android:theme="Theme.Light.NoTitleBar.Fullscreen"  //白色背景,無標題欄,全屏    
  5. android:theme="Theme.Black"                        //背景黑色    

 

     名稱爲"Theme"屬性(系統默認的Theme)的定義爲(僅copy部分關於Window屬性的定義) : 

                  文件位於:frameworks\base\core\res\res\values\themes.xml

 

[java]  view plain copy print ?
  1. <style name="Theme">  
  2.   <!-- Window attributes -->  
  3.   <item name="windowBackground">@android:drawable/screen_background_dark</item>  
  4.   <item name="windowFrame">@null</item>  
  5.   <item name="windowNoTitle">false</item>  
  6.   <item name="windowFullscreen">false</item>  
  7.   <item name="windowIsFloating">false</item>  
  8.   <item name="windowTitleSize">25dip</item>  
  9.   <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground</item>  
  10.   <item name="android:windowAnimationStyle">@android:style/Animation.Activity</item>  
  11.   <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>      
  12. lt;/style>  

 

      該Theme做爲一個超元素集,全部其餘的Style/Theme則繼承了它。例如:咱們關於自定義的Theme必須顯示從

  一個父Theme繼承,以下:

 

[java]  view plain copy print ?
  1. <!--自定義Theme 必須制定parent屬性-->  
  2. <style name="CustomTheme" parent="@android:style/Theme" >  
  3.    <item name="android:windowNoTitle">true</item>  
  4.    <item name="android:windowFrame">@drawable/icon</item>  
  5.    <item name="android:windowBackground">?android:windowFrame</item>  
  6. </style>  
        咱們看看Android另一個Theme.NoTitleBar屬性定義,默認繼承了"Theme"集合。

 

[java]  view plain copy print ?
  1. <!-- Variant of the default (dark) theme with no title bar -->  
  2.    <style name="Theme.NoTitleBar">  
  3.        <item name="android:windowNoTitle">true</item>  
  4.    </style>  

 


    其實xml文件中聲明的任何元素(包括屬性),必須經過代碼去獲取他們的值,而後進行適當地邏輯運算。那麼

 系統是在什麼地方去解析這些Window屬性,而且選擇合適地佈局文件?

 

 

2、Theme主題的解析以及佈局文件的選取

 

 

      若是對setContentView()調用過程不太熟悉的朋友,能夠先看看前面一篇博文<從setContentView()談起>

 今天咱們深刻到其中generateLayout()方法,該方法地主要做用就是解析這些Window屬性,而後選擇合適地

  佈局文件做爲咱們地Activity或者Window界面地承載佈局文件,即DecorView的直接子View。

 

    在進行具體分析以前,Android還提供了另外兩種簡單API讓咱們制定界面的風格,以下兩個方法:
    
     一、requestFeature() 設定個該界面的風格Feature,例如,FEATURE_NO_TITLE(沒有標題) 、 

       FEATURE_PROGRESS(標題欄帶進度條) 。必須在setContentView()前調用,不然會報異常。 

            FEATURE屬性定義在Window.java類
          
    二、getWindow().setFlags(),爲當前的WindowManager.LayoutParams添加一些Flag。

            Flag標記定義在WindowManager.LayoutParams.java類。

      
   經過這兩種方法隱藏狀態欄和標題欄的例子爲:

 

[java]  view plain copy print ?
  1. @Override  
  2. public void onCreate(Bundle savedInstanceState) {  
  3.     super.onCreate(savedInstanceState);  
  4.     // hide titlebar of application  
  5.     // must be before setting the layout  
  6.     requestWindowFeature(Window.FEATURE_NO_TITLE);  
  7.     // hide statusbar of Android  
  8.     // could also be done later  
  9.     getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,  
  10.             WindowManager.LayoutParams.FLAG_FULLSCREEN);  
  11.     setContentView(R.layout.main);  
  12. }  
    完整例子,可見於博文 <Android隱藏狀態欄和標題欄,至關於全屏效果>

 

      源碼分析:

         這兩個方法是在Window.java類實現的,以下:

[java]  view plain copy print ?
  1. public class Window {  
  2.      /** Flag for the "options panel" feature.  This is enabled by default. */  
  3.     public static final int FEATURE_OPTIONS_PANEL = 0;  
  4.     /** Flag for the "no title" feature, turning off the title at the top 
  5.      *  of the screen. */  
  6.     public static final int FEATURE_NO_TITLE = 1;      
  7.     /** Flag for the progress indicator feature */  
  8.     public static final int FEATURE_PROGRESS = 2;  
  9.     /** Flag for having an icon on the left side of the title bar */  
  10.     public static final int FEATURE_LEFT_ICON = 3;  
  11.     /** Flag for having an icon on the right side of the title bar */  
  12.     public static final int FEATURE_RIGHT_ICON = 4;  
  13.     /** Flag for indeterminate progress */  
  14.     public static final int FEATURE_INDETERMINATE_PROGRESS = 5;  
  15.     /** Flag for the context menu.  This is enabled by default. */  
  16.     public static final int FEATURE_CONTEXT_MENU = 6;      // 菜單  
  17.     /** Flag for custom title. You cannot combine this feature with other title features. */  
  18.     public static final int FEATURE_CUSTOM_TITLE = 7;  
  19.       
  20.     //默認的FEATURES FEATURE_OPTIONS_PANEL & FEATURE_CONTEXT_MENU   
  21.     protected static final int DEFAULT_FEATURES = (1 << FEATURE_OPTIONS_PANEL) |  
  22.             (1 << FEATURE_CONTEXT_MENU);  
  23.     //局部變量保存  保存設置的Feature ,按位操做。  
  24.     private int mFeatures = DEFAULT_FEATURES;  
  25.       
  26.     //設置Feature , 按位操做添加進去  
  27.     public boolean requestFeature(int featureId) {  
  28.         final int flag = 1<<featureId;      
  29.         mFeatures |= flag;    
  30.         //當該Activity是不是某個Activity的子Activity,mContainer即表明父Activity的Window對象,通常爲null  
  31.         mLocalFeatures |= mContainer != null ? (flag&~mContainer.mFeatures) : flag;  
  32.         return (mFeatures&flag) != 0;  
  33.     }  
  34.       
  35.     public void addFlags(int flags) {  
  36.         setFlags(flags, flags);  
  37.     }  
  38.      
  39.     /** 
  40.      * Set the flags of the window, as per the 
  41.      * {@link WindowManager.LayoutParams WindowManager.LayoutParams} 
  42.      * flags. 
  43.      * <p>Note that some flags must be set before the window decoration is 
  44.      * created . 
  45.      * These will be set for you based on the {@link android.R.attr#windowIsFloating} 
  46.      * attribute. 
  47.      * @param flags The new window flags (see WindowManager.LayoutParams). 
  48.      * @param mask Which of the window flag bits to modify. 
  49.      */  
  50.     //mask表明對應爲的掩碼,設置對應位時,須要先清空對應位的掩碼,而後在進行或操做。相似的函數能夠見於View.java類的setFlags()方法  
  51.     public void setFlags(int flags, int mask) {  
  52.         final WindowManager.LayoutParams attrs = getAttributes(); //當前的WindowManager.LayoutParams屬性  
  53.         //將設置的flags添加至attrs屬性中  
  54.         attrs.flags = (attrs.flags&~mask) | (flags&mask);    
  55.         mForcedWindowFlags |= mask;  
  56.         if (mCallback != null) {    //Activity 和 Dialog 默認實現了Window.Callback接口  
  57.             mCallback.onWindowAttributesChanged(attrs);  //回調onWindowAttributesChanged()方法  
  58.         }  
  59.     }  
  60.     ...  
  61. }       

 

   其實也挺簡單的,主要是邏輯運算符的操做。
          mFeatures  表明了當前Window的Feature值.
          flags           保存在當前WindowManager.LayoutParams.flag屬性中。

 

  接下來具體分析generateLayout()方法.

        若是當前界面的DecorView對象爲空(通常由setContentView()或者addContentView()調用),則會建立一個

   DecorView對象以及對應的裝載xml佈局的mContentParent對象。

 

    Step 1、建立DecorView對象

 

[java]  view plain copy print ?
  1. private void installDecor() {  
  2.     if (mDecor == null) {  
  3.         mDecor = generateDecor();  //建立一個DecorView對象  
  4.         mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);  //設置焦點捕獲動做  
  5.     }  
  6.       
  7.     if (mContentParent == null) { //mContentParent做爲咱們自定義佈局的Parent.  
  8.         mContentParent = generateLayout(mDecor);  //建立mContentParent。  
  9.         ...  
  10.     }  
  11. }  

       Step 2、建立mContentParent對象

 

 

[java]  view plain copy print ?
  1. protected ViewGroup generateLayout(DecorView decor) {  
  2.     // Apply data from current theme.  
  3.     TypedArray a = getWindowStyle();   //得到當前的Theme屬性對應的TypedArray對象.  
  4.        
  5.     //接下來都是對Attribute值的獲取...,後續繼續分析  
  6.     //是不是Dialog樣式的界面 , android:windowIsFloating屬性  
  7.     mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);  
  8.     ...  
  9. }  

 

    首先獲取系統自定義的Style對應的TypeArray對象,而後獲取對應的屬性值。咱們繼續分析getWindowStyle()

 方法。

      2.一、

[java]  view plain copy print ?
  1. /** 
  2.  * Return the {@link android.R.styleable#Window} attributes from this 
  3.  * window's theme. 
  4.  */  
  5. public final TypedArray getWindowStyle() {  
  6.     synchronized (this) {  
  7.         if (mWindowStyle == null) {  
  8.             //調用Context類的相應方法,返回對應的TypedArray對象,參數爲自定義屬性集合  <declare-styleable name="Window">  
  9.             mWindowStyle = mContext.obtainStyledAttributes(com.android.internal.R.styleable.Window);  
  10.         }  
  11.         return mWindowStyle;  
  12.     }  
  13. }  
        調用Context類對應地obtainStyledAttributes()方法,參數傳遞的是 Window對應的自定義屬性集合。

 

   2.二、

 

[java]  view plain copy print ?
  1. /** 
  2.  * Retrieve styled attribute information in this Context's theme.  See 
  3.  * {@link Resources.Theme#obtainStyledAttributes(int[])} 
  4.  * for more information. 
  5.  * 
  6.  * @see Resources.Theme#obtainStyledAttributes(int[]) 
  7.  */  
  8. public final TypedArray obtainStyledAttributes(  
  9.         int[] attrs) {  
  10.     //首先獲取當前Theme對應的TypedArray對象  
  11.     return getTheme().obtainStyledAttributes(attrs);  
  12. }  
           因爲Activity繼承至ContextThemeWapprer類,ContextThemeWapprer重寫了getTheme()方法。

 

     2.3

 

[java]  view plain copy print ?
  1. @Override   
  2. public Resources.Theme getTheme() {  
  3.     if (mTheme != null) {              //第一次訪問時,mTheme對象爲null  
  4.         return mTheme;  
  5.     }  
  6.     // Theme 資源是否已經指定,沒有選取默認Theme  
  7.     if (mThemeResource == 0) {          
  8.         mThemeResource = com.android.internal.R.style.Theme;  
  9.     }  
  10.     initializeTheme();   //初始化Theme資源  
  11.     return mTheme;  
  12. }  
      首先,判斷是不是第一次調用該方法,便是否建立了mTheme對象;

 

     其次,判斷是否設置了該Theme所對應的資源ID,若是沒有,則選取默認的theme style 

            即com.android.internal.R.style.Theme 。

      最後,初始化對應資源。

 

[java]  view plain copy print ?
  1. /** 
  2.  * Called by {@link #setTheme} and {@link #getTheme} to apply a theme 
  3.  * resource to the current Theme object.  Can override to change the 
  4.  * default (simple) behavior.  This method will not be called in multiple 
  5.  * threads simultaneously. 
  6.  * 
  7.  * @param theme The Theme object being modified. 
  8.  * @param resid The theme style resource being applied to <var>theme</var>. 
  9.  * @param first Set to true if this is the first time a style is being 
  10.  *              applied to <var>theme</var>. 
  11.  */  
  12. protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {  
  13.     theme.applyStyle(resid, true);  
  14. }  
  15.   
  16. private void initializeTheme() {  
  17.     final boolean first = mTheme == null;     //是不是第一次調用  
  18.     if (first) {  
  19.         mTheme = getResources().newTheme();     
  20.         Resources.Theme theme = mBase.getTheme();  //調用ContextImpl類的getTheme(),獲取默認的Theme  
  21.         if (theme != null) {  
  22.             mTheme.setTo(theme);   //將theme配置應用到mTheme屬性中  
  23.         }  
  24.     }  
  25.     onApplyThemeResource(mTheme, mThemeResource, first);  
  26. }  

 

      若是沒有手動設置mThemeResource,則選取系統中爲咱們提供的默認Theme。固然咱們也能夠手動設置Theme 

 Resource ,如開篇所述。

            方法一: Activity中調用setTheme()方法,該方法會實如今ContextThemeWrapper.java類中。

 

[java]  view plain copy print ?
  1. @Override   
  2. public void setTheme(int resid) {  
  3.     mThemeResource = resid;    //設置mThemeResource  
  4.     initializeTheme();  
  5. }  

 

         方法二:在AndroidManifest文件中,爲Activity節點配置android:theme屬性. 當經過startActivity()啓動一個

 Activity時,會調用setTheme()方法。文件路徑:frameworks\base\core\java\android\app\ActivityThread.java

 

[java]  view plain copy print ?
  1. private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {  
  2.     ...  
  3.     Activity activity = null;  
  4.     try {  
  5.         //建立Activity實例  
  6.         java.lang.ClassLoader cl = r.packageInfo.getClassLoader();  
  7.         activity = mInstrumentation.newActivity(  
  8.                 cl, component.getClassName(), r.intent);  
  9.     }   
  10.     ...  
  11.     try {  
  12.         ...  
  13.         if (activity != null) {  
  14.             //建立相應的信息.  
  15.             ContextImpl appContext = new ContextImpl();  
  16.             appContext.init(r.packageInfo, r.token, this);  
  17.             appContext.setOuterContext(activity);  
  18.             CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());  
  19.             ...     
  20.             activity.attach(appContext, this, getInstrumentation(), r.token,  
  21.                     r.ident, app, r.intent, r.activityInfo, title, r.parent,  
  22.                     r.embeddedID, r.lastNonConfigurationInstance,  
  23.                     r.lastNonConfigurationChildInstances, config);  
  24.             ...  
  25.             //activityInfo相關信息是由ActivityManagerService經過IPC調用而來  
  26.             //能夠參考Android SDK的ActivityInfo類 API。  
  27.             int theme = r.activityInfo.getThemeResource();  
  28.             if (theme != 0) {  
  29.                 activity.setTheme(theme); //調用setTheme()方法,參見方法1  
  30.             }  
  31.       ...  
  32.         }  
  33.     }  
  34.     ...    
  35.     return activity;  
  36. }  

     總結: 若是沒有爲設置Theme Resource ,則會選取默認的Theme Style,不然選用咱們設置的Theme。

 

         由於mTheme對象是相對統一的,只不過每次都經過apply一個新的Style ID,感受Android 框架會爲每一個

  應用程序的資源造成一個統一的資源庫,應用程序定義的全部Style都存在在該資源庫中,能夠經過經過Style 

  ID值顯示獲取對應值集合。 但因爲對系統獲取資源的過程不瞭解,目前還不清楚Android中是如何根據資源ID

  獲取對應的資源甚至一組資源的。但可喜的是,老羅目前正在研究這塊,但願能在老羅的文章中找到答案。

              具體可見 <

Android資源管理框架(Asset Manager)簡要介紹和學習計劃

>

 

 

  

     另外,Dialog的構造函數也有必定啓發性,建立了一個指定Theme 的ContextThemeWapper對象,而後經過它創

  建對應的Window對象。 具體過程能夠自行研究下。

 

[java]  view plain copy print ?
  1. public Dialog(Context context, int theme) {  
  2.     //建立一個ContextThemeWrapper對象,指定 Theme ID  
  3.     mContext = new ContextThemeWrapper(  
  4.         context, theme == 0 ? com.android.internal.R.style.Theme_Dialog : theme);  
  5.     mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);  
  6.     //傳遞該ContextThemeWrapper對象,構造指定的ID.  
  7.     Window w = PolicyManager.makeNewWindow(mContext);  
  8.     ...  
  9. }  

 

    PS : Android 4.0 以後默認的屬性爲Theme_Holo,呵呵,Holo倒挺有意思的。調用相關函數時,會判斷SDK 

版本,而後選取相應地Theme。相關函數以下:   @ Resources.java 

 

[java]  view plain copy print ?
  1. /** @hide */  
  2. public static int selectDefaultTheme(int curTheme, int targetSdkVersion) {  
  3.     return selectSystemTheme(curTheme, targetSdkVersion,  
  4.             com.android.internal.R.style.Theme,  
  5.             com.android.internal.R.style.Theme_Holo,  
  6.             com.android.internal.R.style.Theme_DeviceDefault);  
  7. }  
  8. /** @hide */  
  9. public static int selectSystemTheme(int curTheme, int targetSdkVersion,  
  10.         int orig, int holo, int deviceDefault) {  
  11.     //是否設置了Theme  
  12.     if (curTheme != 0) {  
  13.         return curTheme;  
  14.     }  
  15.     //判斷版本號 , HONEYCOMB 表明 Android 3.0 , ICE_CREAM_SANDWICH 表明 Android 4.0   
  16.     if (targetSdkVersion < Build.VERSION_CODES.HONEYCOMB) {  
  17.         return orig;  
  18.     }  
  19.     if (targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {  
  20.         return holo;  
  21.     }  
  22.     return deviceDefault;  
  23. }  


 

 

  Step 3、經過前面的分析,咱們獲取了Window屬性對應的TypeArray對象,接下來就是獲取對應的屬性值。

 以下代碼所示:

 

[java]  view plain copy print ?
  1.    
  2. protected ViewGroup generateLayout(DecorView decor) {  
  3.     // Apply data from current theme.  
  4.     TypedArray a = getWindowStyle();   //得到當前的Theme屬性對應的TypedArray對象.  
  5.        
  6.     //是不是Dialog樣式的界面 , android:windowIsFloating屬性  
  7.     mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);  
  8.     int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)   
  9.         & (~getForcedWindowFlags());  
  10.     //若是是Dialog樣式,則設置當前的WindowManager.LayoutParams的width和height值,表明該界面的大小由佈局文件大小指定。  
  11.     // 由於默認的WindowManager.LayoutParams的width和height是MATCH_PARENT,即與屏幕大小一致.  
  12.     if (mIsFloating) {   
  13.         setLayout(WRAP_CONTENT, WRAP_CONTENT);   
  14.         setFlags(0, flagsToUpdate); //取消FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR 位標記  
  15.     } else {  
  16.         setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);  
  17.     }  
  18.     //是不是沒有標題欄 , android:windowNoTitle屬性  
  19.     if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) {  
  20.         requestFeature(FEATURE_NO_TITLE); //添加FEATURE_NO_TITLE  
  21.     }  
  22.     //是不是全屏, android:windowFullscreen屬性  
  23.     if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {  
  24.         setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags()));  
  25.     }  
  26.     //是不是顯示牆紙, android:windowShowWallpaper屬性  
  27.     if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {  
  28.         setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));  
  29.     }  
  30.     WindowManager.LayoutParams params = getAttributes(); //當前的WindowManager.LayoutParams對象  
  31.     if (!hasSoftInputMode()) {  //是否已經設置了softInputMode模式,可顯示經過#setSoftInputMode()方法設定  
  32.         params.softInputMode = a.getInt(  
  33.                 com.android.internal.R.styleable.Window_windowSoftInputMode,//android:windowSoftInputMode  
  34.                 params.softInputMode);  //能夠由 WindowManager.LayoutParams指定  
  35.     }  
  36.     //是不是某個Activity的子Activity,通常不是,getContainer()返回  null.  
  37.     if (getContainer() == null) {    
  38.         if (mBackgroundDrawable == null) {   //得到了指定的背景圖片.  
  39.             if (mBackgroundResource == 0) {  //得到了指定的背景圖片資源  
  40.                 mBackgroundResource = a.getResourceId(  //背景圖片id ,  android:windowBackground  
  41.                         com.android.internal.R.styleable.Window_windowBackground, 0);  
  42.             }  
  43.         }  
  44.         ...  
  45.     }  
  46.     // Inflate the window decor.  
  47.     int layoutResource;  
  48.     int features = getLocalFeatures(); // 等同於mFeatures,由requestFeature()設定.  
  49.     if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {  
  50.         //一、判斷是否爲對話框樣式  
  51.         if (mIsFloating) {  
  52.             layoutResource = com.android.internal.R.layout.dialog_title_icons;  
  53.         } else {  
  54.             layoutResource = com.android.internal.R.layout.screen_title_icons;  
  55.         }  
  56.     }    
  57.     else if { //二、進度條樣式  ;  //三、自定義Title}  
  58.     else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {  
  59.         //四、沒有標題欄  
  60.         // If no other features and not embedded, only need a title.  
  61.         // If the window is floating, we need a dialog layout  
  62.         if (mIsFloating) {  
  63.             layoutResource = com.android.internal.R.layout.dialog_title;  
  64.         } else {  
  65.             layoutResource = com.android.internal.R.layout.screen_title;  
  66.         }  
  67.         // System.out.println("Title!");  
  68.     } else {  
  69.         layoutResource = com.android.internal.R.layout.screen_simple;  
  70.     }  
  71.     View in = mLayoutInflater.inflate(layoutResource, null);  
  72.     decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));  
  73.     ...  
  74.     if (getContainer() == null) {  
  75.         Drawable drawable = mBackgroundDrawable;     
  76.         if (mBackgroundResource != 0) {        //獲取背景圖片資源  
  77.             drawable = getContext().getResources().getDrawable(mBackgroundResource);  
  78.         }  
  79.         mDecor.setWindowBackground(drawable); //爲DecorView設置背景圖片  
  80.         drawable = null;  
  81.         //判斷是否須要設置WindowFrame圖片,該資源表明一個前景foreground圖片,相對於背景background圖片,  
  82.         if (mFrameResource != 0) {        //默認爲null ,<item name="windowFrame">@null</item>  
  83.             drawable = getContext().getResources().getDrawable(mFrameResource);  
  84.         }  
  85.         mDecor.setWindowFrame(drawable);  
  86.     }  
  87.     return contentParent;               
  88. }  

 

       依次取出對應的屬性值,而後根據這些值調用不一樣的函數,例如:requestFeature(),以及爲

  WindowMamager.LayoutParams設置Flag標記(這個掩碼實現按位操做倒挺麻煩的,部分理解,有知道的朋友

  能夠給我指點下。)例如:若是是對話框窗口,則不設置FLAG_LAYOUT_IN_SCREEN |   FLAG_LAYOUT_INSET_DECOR

  位標記,由於該標記表明對應的是Activity窗口。

         一、  FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR   表明的是典型的Activity窗口
         二、 FLAG_LAYOUT_IN_SCREEN                                                             表明的是典型的全屏窗口

         三、 其餘則表明其餘對話框窗口。

      最後,根據相應的Feature值,加載不一樣的佈局文件。

 

    PS : 前些日子在論壇中看到有網友說取消/隱藏ActionBar,Android 4.0中對一個支持ActionBar的資源文件

  定義以下:    文件路徑  frameworks\base\core\res\res\layout\screen_action_bar.xml

 

[java]  view plain copy print ?
  1. <!--  
  2. This is an optimized layout for a screen with the Action Bar enabled.  
  3. -->  
  4.   
  5. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  6.     android:orientation="vertical"  
  7.     android:fitsSystemWindows="true">  
  8.     <!-- Action Bar 對應的 View文件 -->  
  9.     <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"  
  10.         android:layout_width="match_parent"  
  11.         android:layout_height="wrap_content"  
  12.         style="?android:attr/actionBarStyle">  
  13.         <com.android.internal.widget.ActionBarView  
  14.             android:id="@+id/action_bar"  
  15.             android:layout_width="match_parent"  
  16.             android:layout_height="wrap_content"  
  17.             style="?android:attr/actionBarStyle" />  
  18.         <com.android.internal.widget.ActionBarContextView  
  19.             android:id="@+id/action_context_bar"  
  20.             android:layout_width="match_parent"  
  21.             android:layout_height="wrap_content"  
  22.             android:visibility="gone"  
  23.             style="?android:attr/actionModeStyle" />  
  24.     </com.android.internal.widget.ActionBarContainer>  
  25.     <FrameLayout android:id="@android:id/content"  
  26.         android:layout_width="match_parent"   
  27.         android:layout_height="0dip"  
  28.         android:layout_weight="1"  
  29.         android:foregroundGravity="fill_horizontal|top"  
  30.         android:foreground="?android:attr/windowContentOverlay" />  
  31.     <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"  
  32.                   android:layout_width="match_parent"  
  33.                   android:layout_height="wrap_content"  
  34.                   style="?android:attr/actionBarSplitStyle"  
  35.                   android:visibility="gone"  
  36.                   android:gravity="center"/>  
  37. </LinearLayout>  

 

    具體分析依舊見於generateLayout @ PhoneWindow.java ,  4.0 的源碼咯。直接設置爲gone狀態不知可行否?

 

 轉載請註明出處:http://blog.csdn.net/qinjuning

相關文章
相關標籤/搜索