1. 程式人生 > >為什麼requestWindowFeature()方法要在setContentView()方法之前呼叫?

為什麼requestWindowFeature()方法要在setContentView()方法之前呼叫?

日常開發中偶爾遇到需要修改標題欄樣式的情況,這個時候就需要用到requestWindowFeature(int featureId)來設定視窗樣式。

featureId有如下幾種值:
1. DEFAULT_FEATURES:系統預設狀態,一般不需要指定
2. FEATURE_CONTEXT_MENU:啟用ContextMenu,預設該項已啟用,一般無需指定
3. FEATURE_CUSTOM_TITLE:自定義標題。當需要自定義標題時必須指定。如:標題是一個按鈕時
4. FEATURE_INDETERMINATE_PROGRESS:不確定的進度
5. FEATURE_LEFT_ICON:標題欄左側的圖示
6. FEATURE_NO_TITLE:無標題
7. FEATURE_OPTIONS_PANEL:啟用“選項面板”功能,預設已啟用。
8. FEATURE_PROGRESS:進度指示器功能
9. FEATURE_RIGHT_ICON:標題欄右側的圖示
各自的樣式大家可以自己嘗試一下,我們這次只是探討為什麼requestWindowFeature方法要在setContentView()方法之前呼叫。

要理解為什麼requestWindowFeature()方法要在setContentView()方法之前呼叫,我們首先要看一下Android的視窗的UI架構。
Activity的UI架構
如圖所示,每個Activity中都包含一個Window類的物件,一般這個Window類的物件是由PhoneWindow實現的,也就是Avtivity內部有一個PhoneWindow的物件。而這個PhoneWindow物件會將一個DecorView物件設定成整個視窗的根View。這樣看來也就說,整個Activity顯示的是一個DecorView。而在DecorView內部將顯示內容分為TitleView和ContentView兩個部分。ContentView大家都比較熟悉,它是一個ID為content的FrameLayout,我們通過setContentView()設定的佈局就會被新增到這個FrameLayout上。
這裡寫圖片描述


DecorView中的佈局關係如上圖,我們看一下setContentView方法的程式碼。

    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

首先它會設定FrameLayout的佈局,之後回初始化ActionBar。看到這裡我們就明白了,如果在setContentView方法之後設定requestWindowFeature()方法的話,由於已經初始化了ActionBar,所以並不會引起UI顯示上的變化,必須在setContentView之前呼叫requestWindowFeature()方法才能在ActionBar初始化的時候影響它的顯示。