您的位置:首页 > 其它

Andriod中Style/Theme原理以及Activity界面文件选取过程浅析

2015-02-03 14:58 337 查看
通过对前面的一篇博文<从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

[java] view plaincopyprint?

<!-- 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

[java] view plaincopyprint?

<!-- 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 ,常见的有如下 :

[java] view plaincopyprint?

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

[java] view plaincopyprint?

<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继承,如下:

[java] view plaincopyprint?

<!--自定义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>

我们看看Android另外一个Theme.NoTitleBar属性定义,默认继承了"Theme"集合。

[java] view plaincopyprint?

<!-- 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类。

通过这两种方法隐藏状态栏和标题栏的例子为:

[java] view plaincopyprint?

@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);

}

完整例子,可见于博文<Android隐藏状态栏和标题栏,相当于全屏效果>

源码分析:

这两个方法是在Window.java类实现的,如下:

[java] view plaincopyprint?

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对象

[java] view plaincopyprint?

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对象

[java] view plaincopyprint?

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、

[java] view plaincopyprint?

/**

* 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;

}

}

调用Context类对应地obtainStyledAttributes()方法,参数传递的是 Window对应的自定义属性集合。

2.2、

[java] view plaincopyprint?

/**

* 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);

}

由于Activity继承至ContextThemeWapprer类,ContextThemeWapprer重写了getTheme()方法。

2.3

[java] view plaincopyprint?

@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;

}

首先,判断是否是第一次调用该方法,即是否创建了mTheme对象;

其次,判断是否设置了该Theme所对应的资源ID,如果没有,则选取默认的theme style

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

最后,初始化对应资源。

[java] view plaincopyprint?

/**

* 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类中。

[java] view plaincopyprint?

@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

[java] view plaincopyprint?

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对象。 具体过程可以自行研究下。

[java] view plaincopyprint?

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

[java] view plaincopyprint?

/** @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对象,接下来就是获取对应的属性值。

如下代码所示:

[java] view plaincopyprint?

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

[java] view plaincopyprint?

<!--

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐