通過對前面的一篇博文<從setContentView()談起>的學習,我們掌握了Activity組件布局文件地創建過程以及
其頂層控件DecorView,今天我們繼續庖丁解牛---深入到其中的generateLayout()方法,步步為營掌握一下內容:
1、Activity中Theme(主題)的系統定義以及使用之處;
2、如何根據設置的Feature(屬性)選擇合適的布局文件。
另外,對於下文中Theme和Style的概念進行一個簡要說明:
都是由<style />節點進行定義的。但應用在<application />和<activity />則為theme,應用在<View />則為style.
一、關於Theme主題的使用方法以及原理分析
通常來說,可以直接使用系統定義好的Style/Theme,畢竟,系統為我們提供了豐富地選擇。當然,你也可以
自定義Theme,前提是該Theme必須繼承與某個已經存在地Theme,否則編譯器會提示錯誤的。
1、 應用Theme屬性兩種方式
①、在AndroidManifest.xml文件中在<application/>或者<activity />節點設置android:theme屬性.
②、直接在代碼中調用方法setTheme()設置該Activity的主題,必須得在第一次調用setContentView()前設置,
否則,也是沒有效果的(具體原因可見后面分析)。
2、原理分析
Android的所有系統資源定義位置存放在 frameworks\base\core\res\ 路徑下,編譯時會形成apk文件,即
framework-res.apk,所有應用程序共享。
實際上任何Style/Theme也是一組自定義屬性集合,其內置在Android系統資源中,如下所示:
文件路徑:frameworks\base\core\res\res\values\attrs.xml
- <!-- The set of attributes that describe a Windows's theme. -->
- <declare-styleable name="Window">
- <!-- 常見的Window屬性 -->
- <attr name="windowBackground" /> //該界面所對應的背景圖片, drawable / color
- <attr name="windowFrame" /> //該界面所對應的前景frontground圖片, drawable / color
- <attr name="windowNoTitle" /> //是否帶有title , boolean類型
- <attr name="windowFullscreen" /> //是否全屏 , boolean類型
- <attr name="windowIsFloating" /> //是否是懸浮窗類型 , boolean類型
- <attr name="windowIsTranslucent" /> //是否透明 , boolean類型
- <attr name="windowSoftInputMode" /> //設置鍵盤彈出來的樣式 , 例如: adjustsize 等 ,其實也是int類型
- <!-- more 更多不常見地Window屬性-->
- ...
- </declare-styleable>
特殊的是如果某個自定義屬性如果沒有指名 format屬性,那么該屬性必須在當前已經定義,即該屬性只是一個
別名。
大部分Android屬性定義在 name = "Theme"的屬性集合下(僅列出Window attrs):
文件路徑:frameworks\base\core\res\res\values\attrs.xml
- <!-- These are the standard attributes that make up a complete theme. -->
- <declare-styleable name="Theme">
- <!-- Drawable to use as the overall window background. There are a
- few special considerations you should use when settings this
- drawable:
- -->
- <attr name="windowBackground" format="reference" />
- <!-- Drawable to use as a frame around the window. -->
- <attr name="windowFrame" format="reference" />
- <!-- Flag indicating whether there should be no title on this window. -->
- <attr name="windowNoTitle" format="boolean" />
- <!-- Flag indicating whether this window should fill the entire screen. -->
- <attr name="windowFullscreen" format="boolean" />
- <!-- Flag indicating whether this is a floating window. -->
- <attr name="windowIsFloating" format="boolean" />
- <!-- Flag indicating whether this is a translucent window. -->
- <attr name="windowIsTranslucent" format="boolean" />
- <!-- Flag indicating that this window's background should be the
- user's current wallpaper. -->
- <attr name="windowShowWallpaper" format="boolean" />
- <!-- This Drawable is overlaid over the foreground of the Window's content area, usually
- to place a shadow below the title. -->
- <!-- This Drawable is overlaid over the foreground of the Window's content area, usually
- to place a shadow below the title. -->
- <attr name="windowContentOverlay" format="reference" />
- <!--more -->
- </declare-styleable>
屬性定義如上,Android系統中這些屬性定義了很多Style/Theme ,常見的有如下 :
- android:theme="Theme" //默認地Theme
- android:theme="Theme.Light" //背景為白色
- android:theme="Theme.Light.NoTitleBar" //白色背景並無標題欄
- android:theme="Theme.Light.NoTitleBar.Fullscreen" //白色背景,無標題欄,全屏
- android:theme="Theme.Black" //背景黑色
名稱為"Theme"屬性(系統默認的Theme)的定義為(僅copy部分關於Window屬性的定義) :
文件位於:frameworks\base\core\res\res\values\themes.xml
- <style name="Theme">
- <!-- Window attributes -->
- <item name="windowBackground">@android:drawable/screen_background_dark</item>
- <item name="windowFrame">@null</item>
- <item name="windowNoTitle">false</item>
- <item name="windowFullscreen">false</item>
- <item name="windowIsFloating">false</item>
- <item name="windowTitleSize">25dip</item>
- <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground</item>
- <item name="android:windowAnimationStyle">@android:style/Animation.Activity</item>
- <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
- lt;/style>
該Theme作為一個超元素集,所有其他的Style/Theme則繼承了它。例如:我們關於自定義的Theme必須顯示從
一個父Theme繼承,如下:
- <!--自定義Theme 必須制定parent屬性-->
- <style name="CustomTheme" parent="@android:style/Theme" >
- <item name="android:windowNoTitle">true</item>
- <item name="android:windowFrame">@drawable/icon</item>
- <item name="android:windowBackground">?android:windowFrame</item>
- </style>
- <!-- Variant of the default (dark) theme with no title bar -->
- <style name="Theme.NoTitleBar">
- <item name="android:windowNoTitle">true</item>
- </style>
其實xml文件中聲明的任何元素(包括屬性),必須通過代碼去獲取他們的值,然后進行適當地邏輯運算。那么
系統是在什么地方去解析這些Window屬性,並且選擇合適地布局文件?
二、Theme主題的解析以及布局文件的選取
如果對setContentView()調用過程不太熟悉的朋友,可以先看看前面一篇博文<從setContentView()談起>。
今天我們深入到其中generateLayout()方法,該方法地主要作用就是解析這些Window屬性,然后選擇合適地
布局文件作為我們地Activity或者Window界面地承載布局文件,即DecorView的直接子View。
在進行具體分析之前,Android還提供了另外兩種簡單API讓我們制定界面的風格,如下兩個方法:
1、requestFeature() 設定個該界面的風格Feature,例如,FEATURE_NO_TITLE(沒有標題) 、
FEATURE_PROGRESS(標題欄帶進度條) 。必須在setContentView()前調用,否則會報異常。
FEATURE屬性定義在Window.java類
2、getWindow().setFlags(),為當前的WindowManager.LayoutParams添加一些Flag。
Flag標記定義在WindowManager.LayoutParams.java類。
通過這兩種方法隱藏狀態欄和標題欄的例子為:
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // hide titlebar of application
- // must be before setting the layout
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- // hide statusbar of Android
- // could also be done later
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
- setContentView(R.layout.main);
- }
源碼分析:
這兩個方法是在Window.java類實現的,如下:
- public class Window {
- /** Flag for the "options panel" feature. This is enabled by default. */
- public static final int FEATURE_OPTIONS_PANEL = 0;
- /** Flag for the "no title" feature, turning off the title at the top
- * of the screen. */
- public static final int FEATURE_NO_TITLE = 1;
- /** Flag for the progress indicator feature */
- public static final int FEATURE_PROGRESS = 2;
- /** Flag for having an icon on the left side of the title bar */
- public static final int FEATURE_LEFT_ICON = 3;
- /** Flag for having an icon on the right side of the title bar */
- public static final int FEATURE_RIGHT_ICON = 4;
- /** Flag for indeterminate progress */
- public static final int FEATURE_INDETERMINATE_PROGRESS = 5;
- /** Flag for the context menu. This is enabled by default. */
- public static final int FEATURE_CONTEXT_MENU = 6; // 菜單
- /** Flag for custom title. You cannot combine this feature with other title features. */
- public static final int FEATURE_CUSTOM_TITLE = 7;
- //默認的FEATURES FEATURE_OPTIONS_PANEL & FEATURE_CONTEXT_MENU
- protected static final int DEFAULT_FEATURES = (1 << FEATURE_OPTIONS_PANEL) |
- (1 << FEATURE_CONTEXT_MENU);
- //局部變量保存 保存設置的Feature ,按位操作。
- private int mFeatures = DEFAULT_FEATURES;
- //設置Feature , 按位操作添加進去
- public boolean requestFeature(int featureId) {
- final int flag = 1<<featureId;
- mFeatures |= flag;
- //當該Activity是否是某個Activity的子Activity,mContainer即代表父Activity的Window對象,一般為null
- mLocalFeatures |= mContainer != null ? (flag&~mContainer.mFeatures) : flag;
- return (mFeatures&flag) != 0;
- }
- public void addFlags(int flags) {
- setFlags(flags, flags);
- }
- /**
- * Set the flags of the window, as per the
- * {@link WindowManager.LayoutParams WindowManager.LayoutParams}
- * flags.
- * <p>Note that some flags must be set before the window decoration is
- * created .
- * These will be set for you based on the {@link android.R.attr#windowIsFloating}
- * attribute.
- * @param flags The new window flags (see WindowManager.LayoutParams).
- * @param mask Which of the window flag bits to modify.
- */
- //mask代表對應為的掩碼,設置對應位時,需要先清空對應位的掩碼,然后在進行或操作。類似的函數可以見於View.java類的setFlags()方法
- public void setFlags(int flags, int mask) {
- final WindowManager.LayoutParams attrs = getAttributes(); //當前的WindowManager.LayoutParams屬性
- //將設置的flags添加至attrs屬性中
- attrs.flags = (attrs.flags&~mask) | (flags&mask);
- mForcedWindowFlags |= mask;
- if (mCallback != null) { //Activity 和 Dialog 默認實現了Window.Callback接口
- mCallback.onWindowAttributesChanged(attrs); //回調onWindowAttributesChanged()方法
- }
- }
- ...
- }
其實也挺簡單的,主要是邏輯運算符的操作。
mFeatures 代表了當前Window的Feature值.
flags 保存在當前WindowManager.LayoutParams.flag屬性中。
接下來具體分析generateLayout()方法.
如果當前界面的DecorView對象為空(一般由setContentView()或者addContentView()調用),則會創建一個
DecorView對象以及對應的裝載xml布局的mContentParent對象。
Step 1、創建DecorView對象
- private void installDecor() {
- if (mDecor == null) {
- mDecor = generateDecor(); //創建一個DecorView對象
- mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); //設置焦點捕獲動作
- }
- if (mContentParent == null) { //mContentParent作為我們自定義布局的Parent.
- mContentParent = generateLayout(mDecor); //創建mContentParent。
- ...
- }
- }
Step 2、創建mContentParent對象
- protected ViewGroup generateLayout(DecorView decor) {
- // Apply data from current theme.
- TypedArray a = getWindowStyle(); //獲得當前的Theme屬性對應的TypedArray對象.
- //接下來都是對Attribute值的獲取...,后續繼續分析
- //是否是Dialog樣式的界面 , android:windowIsFloating屬性
- mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);
- ...
- }
首先獲取系統自定義的Style對應的TypeArray對象,然后獲取對應的屬性值。我們繼續分析getWindowStyle()
方法。
2.1、
- /**
- * Return the {@link android.R.styleable#Window} attributes from this
- * window's theme.
- */
- public final TypedArray getWindowStyle() {
- synchronized (this) {
- if (mWindowStyle == null) {
- //調用Context類的相應方法,返回對應的TypedArray對象,參數為自定義屬性集合 <declare-styleable name="Window">
- mWindowStyle = mContext.obtainStyledAttributes(com.android.internal.R.styleable.Window);
- }
- return mWindowStyle;
- }
- }
2.2、
- /**
- * Retrieve styled attribute information in this Context's theme. See
- * {@link Resources.Theme#obtainStyledAttributes(int[])}
- * for more information.
- *
- * @see Resources.Theme#obtainStyledAttributes(int[])
- */
- public final TypedArray obtainStyledAttributes(
- int[] attrs) {
- //首先獲取當前Theme對應的TypedArray對象
- return getTheme().obtainStyledAttributes(attrs);
- }
2.3
- @Override
- public Resources.Theme getTheme() {
- if (mTheme != null) { //第一次訪問時,mTheme對象為null
- return mTheme;
- }
- // Theme 資源是否已經指定,沒有選取默認Theme
- if (mThemeResource == 0) {
- mThemeResource = com.android.internal.R.style.Theme;
- }
- initializeTheme(); //初始化Theme資源
- return mTheme;
- }
其次,判斷是否設置了該Theme所對應的資源ID,如果沒有,則選取默認的theme style
即com.android.internal.R.style.Theme 。
最后,初始化對應資源。
- /**
- * Called by {@link #setTheme} and {@link #getTheme} to apply a theme
- * resource to the current Theme object. Can override to change the
- * default (simple) behavior. This method will not be called in multiple
- * threads simultaneously.
- *
- * @param theme The Theme object being modified.
- * @param resid The theme style resource being applied to <var>theme</var>.
- * @param first Set to true if this is the first time a style is being
- * applied to <var>theme</var>.
- */
- protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {
- theme.applyStyle(resid, true);
- }
- private void initializeTheme() {
- final boolean first = mTheme == null; //是否是第一次調用
- if (first) {
- mTheme = getResources().newTheme();
- Resources.Theme theme = mBase.getTheme(); //調用ContextImpl類的getTheme(),獲取默認的Theme
- if (theme != null) {
- mTheme.setTo(theme); //將theme配置應用到mTheme屬性中
- }
- }
- onApplyThemeResource(mTheme, mThemeResource, first);
- }
如果沒有手動設置mThemeResource,則選取系統中為我們提供的默認Theme。當然我們也可以手動設置Theme
Resource ,如開篇所述。
方法一: Activity中調用setTheme()方法,該方法會實現在ContextThemeWrapper.java類中。
- @Override
- public void setTheme(int resid) {
- mThemeResource = resid; //設置mThemeResource
- initializeTheme();
- }
方法二:在AndroidManifest文件中,為Activity節點配置android:theme屬性. 當通過startActivity()啟動一個
Activity時,會調用setTheme()方法。文件路徑:frameworks\base\core\java\android\app\ActivityThread.java
- private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
- ...
- Activity activity = null;
- try {
- //創建Activity實例
- java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
- activity = mInstrumentation.newActivity(
- cl, component.getClassName(), r.intent);
- }
- ...
- try {
- ...
- if (activity != null) {
- //創建相應的信息.
- ContextImpl appContext = new ContextImpl();
- appContext.init(r.packageInfo, r.token, this);
- appContext.setOuterContext(activity);
- CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
- ...
- activity.attach(appContext, this, getInstrumentation(), r.token,
- r.ident, app, r.intent, r.activityInfo, title, r.parent,
- r.embeddedID, r.lastNonConfigurationInstance,
- r.lastNonConfigurationChildInstances, config);
- ...
- //activityInfo相關信息是由ActivityManagerService通過IPC調用而來
- //可以參考Android SDK的ActivityInfo類 API。
- int theme = r.activityInfo.getThemeResource();
- if (theme != 0) {
- activity.setTheme(theme); //調用setTheme()方法,參見方法1
- }
- ...
- }
- }
- ...
- return activity;
- }
總結: 如果沒有為設置Theme Resource ,則會選取默認的Theme Style,否則選用我們設置的Theme。
因為mTheme對象是相對統一的,只不過每次都通過apply一個新的Style ID,感覺Android 框架會為每個
應用程序的資源形成一個統一的資源庫,應用程序定義的所有Style都存在在該資源庫中,可以通過通過Style
ID值顯示獲取對應值集合。 但由於對系統獲取資源的過程不了解,目前還不清楚Android中是如何根據資源ID
獲取對應的資源甚至一組資源的。但可喜的是,老羅目前正在研究這塊,希望能在老羅的文章中找到答案。
具體可見 <
Android資源管理框架(Asset Manager)簡要介紹和學習計划
>
另外,Dialog的構造函數也有一定啟發性,創建了一個指定Theme 的ContextThemeWapper對象,然后通過它創
建對應的Window對象。 具體過程可以自行研究下。
- public Dialog(Context context, int theme) {
- //創建一個ContextThemeWrapper對象,指定 Theme ID
- mContext = new ContextThemeWrapper(
- context, theme == 0 ? com.android.internal.R.style.Theme_Dialog : theme);
- mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
- //傳遞該ContextThemeWrapper對象,構造指定的ID.
- Window w = PolicyManager.makeNewWindow(mContext);
- ...
- }
PS : Android 4.0 之后默認的屬性為Theme_Holo,呵呵,Holo倒挺有意思的。調用相關函數時,會判斷SDK
版本,然后選取相應地Theme。相關函數如下: @ Resources.java
- /** @hide */
- public static int selectDefaultTheme(int curTheme, int targetSdkVersion) {
- return selectSystemTheme(curTheme, targetSdkVersion,
- com.android.internal.R.style.Theme,
- com.android.internal.R.style.Theme_Holo,
- com.android.internal.R.style.Theme_DeviceDefault);
- }
- /** @hide */
- public static int selectSystemTheme(int curTheme, int targetSdkVersion,
- int orig, int holo, int deviceDefault) {
- //是否設置了Theme
- if (curTheme != 0) {
- return curTheme;
- }
- //判斷版本號 , HONEYCOMB 代表 Android 3.0 , ICE_CREAM_SANDWICH 代表 Android 4.0
- if (targetSdkVersion < Build.VERSION_CODES.HONEYCOMB) {
- return orig;
- }
- if (targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- return holo;
- }
- return deviceDefault;
- }
Step 3、通過前面的分析,我們獲取了Window屬性對應的TypeArray對象,接下來就是獲取對應的屬性值。
如下代碼所示:
- protected ViewGroup generateLayout(DecorView decor) {
- // Apply data from current theme.
- TypedArray a = getWindowStyle(); //獲得當前的Theme屬性對應的TypedArray對象.
- //是否是Dialog樣式的界面 , android:windowIsFloating屬性
- mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);
- int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
- & (~getForcedWindowFlags());
- //如果是Dialog樣式,則設置當前的WindowManager.LayoutParams的width和height值,代表該界面的大小由布局文件大小指定。
- // 因為默認的WindowManager.LayoutParams的width和height是MATCH_PARENT,即與屏幕大小一致.
- if (mIsFloating) {
- setLayout(WRAP_CONTENT, WRAP_CONTENT);
- setFlags(0, flagsToUpdate); //取消FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR 位標記
- } else {
- setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
- }
- //是否是沒有標題欄 , android:windowNoTitle屬性
- if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) {
- requestFeature(FEATURE_NO_TITLE); //添加FEATURE_NO_TITLE
- }
- //是否是全屏, android:windowFullscreen屬性
- if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {
- setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags()));
- }
- //是否是顯示牆紙, android:windowShowWallpaper屬性
- if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
- setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));
- }
- WindowManager.LayoutParams params = getAttributes(); //當前的WindowManager.LayoutParams對象
- if (!hasSoftInputMode()) { //是否已經設置了softInputMode模式,可顯示通過#setSoftInputMode()方法設定
- params.softInputMode = a.getInt(
- com.android.internal.R.styleable.Window_windowSoftInputMode,//android:windowSoftInputMode
- params.softInputMode); //可以由 WindowManager.LayoutParams指定
- }
- //是否是某個Activity的子Activity,一般不是,getContainer()返回 null.
- if (getContainer() == null) {
- if (mBackgroundDrawable == null) { //獲得了指定的背景圖片.
- if (mBackgroundResource == 0) { //獲得了指定的背景圖片資源
- mBackgroundResource = a.getResourceId( //背景圖片id , android:windowBackground
- com.android.internal.R.styleable.Window_windowBackground, 0);
- }
- }
- ...
- }
- // Inflate the window decor.
- int layoutResource;
- int features = getLocalFeatures(); // 等同於mFeatures,由requestFeature()設定.
- if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
- //1、判斷是否為對話框樣式
- if (mIsFloating) {
- layoutResource = com.android.internal.R.layout.dialog_title_icons;
- } else {
- layoutResource = com.android.internal.R.layout.screen_title_icons;
- }
- }
- else if { //2、進度條樣式 ; //3、自定義Title}
- else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
- //4、沒有標題欄
- // If no other features and not embedded, only need a title.
- // If the window is floating, we need a dialog layout
- if (mIsFloating) {
- layoutResource = com.android.internal.R.layout.dialog_title;
- } else {
- layoutResource = com.android.internal.R.layout.screen_title;
- }
- // System.out.println("Title!");
- } else {
- layoutResource = com.android.internal.R.layout.screen_simple;
- }
- View in = mLayoutInflater.inflate(layoutResource, null);
- decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
- ...
- if (getContainer() == null) {
- Drawable drawable = mBackgroundDrawable;
- if (mBackgroundResource != 0) { //獲取背景圖片資源
- drawable = getContext().getResources().getDrawable(mBackgroundResource);
- }
- mDecor.setWindowBackground(drawable); //為DecorView設置背景圖片
- drawable = null;
- //判斷是否需要設置WindowFrame圖片,該資源代表一個前景foreground圖片,相對於背景background圖片,
- if (mFrameResource != 0) { //默認為null ,<item name="windowFrame">@null</item>
- drawable = getContext().getResources().getDrawable(mFrameResource);
- }
- mDecor.setWindowFrame(drawable);
- }
- return contentParent;
- }
依次取出對應的屬性值,然后根據這些值調用不同的函數,例如:requestFeature(),以及為
WindowMamager.LayoutParams設置Flag標記(這個掩碼實現按位操作倒挺麻煩的,部分理解,有知道的朋友
可以給我指點下。)例如:如果是對話框窗口,則不設置FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR
位標記,因為該標記代表對應的是Activity窗口。
1、 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR 代表的是典型的Activity窗口
2、 FLAG_LAYOUT_IN_SCREEN 代表的是典型的全屏窗口
3、 其他則代表其他對話框窗口。
最后,根據相應的Feature值,加載不同的布局文件。
PS : 前些日子在論壇中看到有網友說取消/隱藏ActionBar,Android 4.0中對一個支持ActionBar的資源文件
定義如下: 文件路徑 frameworks\base\core\res\res\layout\screen_action_bar.xml
- <!--
- This is an optimized layout for a screen with the Action Bar enabled.
- -->
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:fitsSystemWindows="true">
- <!-- Action Bar 對應的 View文件 -->
- <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="?android:attr/actionBarStyle">
- <com.android.internal.widget.ActionBarView
- android:id="@+id/action_bar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="?android: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="?android:attr/actionModeStyle" />
- </com.android.internal.widget.ActionBarContainer>
- <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" />
- <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="?android:attr/actionBarSplitStyle"
- android:visibility="gone"
- android:gravity="center"/>
- </LinearLayout>
具體分析依舊見於generateLayout @ PhoneWindow.java , 4.0 的源碼咯。直接設置為gone狀態不知可行否?
轉載請注明出處:http://blog.csdn.net/qinjuning