1.1 问题
要在应用程序中使用最新的ActionBar模式,同时保持向后兼容旧设备;此外,还要定制外观以符合应用程序的主题。
1.2 解决方案
(API Level 7)
ActionBar在ActionBar3.0(API Level 11)SDK中被引入,但可以通过Android支持库的AppCompat组件内的ActionBarActivity向后移植到较早的版本。使用ActionBarActivity以及AppCompat中包含的样式和资源,就可以将操作栏放入目标平台为Android2.1和之后版本的应用程序中。
要点:
ActionBarActivity仅在AppCompat库中提供,AppCompat库是Android支持库的一部分;它不是任意平台级别中的原生SDK的一部分。然而,目标平台为API Level 7或之后版本的任意应用程序都可以通过包含支持库使用此小部件。有关在项目中包含支持库的更多信息,请参考以下网址:http://developer.android.com/tools/support-library/index.html。
ActionBar是顶层窗口装饰的一部分,这意味着应用程序内容始终在其下方显示。因此,很难在ActionBar上绘制内容或对ActionBar的位置制作动画。如果必须执行上述操作,则使用Toolbar代替传统的ActionBar。工具栏位于布局内部,因此可控制它的所在位置。给定工具栏引用,Activity会将此视图视为装饰用的ActionBar。
注意:
Toolbar在API Level21中引入,但它也在AppCompat中提供。
##1.3 实现机制
下图显示了适当放置标准ActionBar的Activity。
为了将ActionBar添加到窗口装饰,只需要对启用的ActionBar的Activity应用某个主题。所有默认的Holo和Material原生主题都包括ActionBar,AppCompat中也是如此。请注意,ActionBar的左侧是标题和副标题,右侧则是一系列操作按钮。还有一个可选的Up导航按钮,可以启用该按钮以提供与Back按钮类似的导航。我们将在后面的章节中更详细讨论这一点。
以下三段代码介绍了如何将AppCompat主题附加到Activity以实现上图中的效果。
ActionBar主题清单
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.androidrecipes.actionbar">
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
<activity
android:name=".SupportActionActivity"
android:label="@string/label_actionbar"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
res/values/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 定义将应用于整个应用程序或至少应用于许多Activity的"主题" -->
<style name="AppTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar">
<!-- 提供装饰主题颜色 -->
<item name="colorPrimary">@color/primaryGreen</item>
<item name="colorPrimaryDark">@color/darkGreen</item>
<item name="colorAccent">@color/accentGreen</item>
</style>
</resources>
res/values/colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="primaryGreen">#259b24</color>
<color name="darkGreen">#0a7e07</color>
<color name="accentGreen">#d0f8ce</color>
</resources>
通过向Activity应用Theme.AppCompat.Light.DarkActionBar,就可以使ActionBar显示出来。我们还可以使用标准颜色主题属性对Activity应用绿色阴影。
右侧的图标由Activity的选项菜单生成,该选项菜单的定义代码(support.xml)如下所示。本章后面将讨论选项菜单的使用;在此添加此菜单仅是处于完整性考虑。在以下代码(ActionBar的设置)中,可以看到如何通过代码设置ActionBar的基本属性。
res/menu/support.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_send"
android:title="@string/action_send"
android:icon="@android:drawable/ic_menu_send"
app:showAsAction="ifRoom" />
<item android:id="@+id/action_settings"
android:title="@string/action_settings"
android:orderInCategory="100"
app:showAsAction="never"/>
</menu>
ActionBar的设置
public class SupportActionActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar actionBar = getSupportActionBar();
//通过“Up”箭头指示符显示主页
actionBar.setDisplayHomeAsUpEnabled(true);
//设置标题文本
actionBar.setTitle("Android Recipes");
//设置副标题文本
actionBar.setSubtitle("ActionBar Recipes");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.support, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Toast.makeText(this, "Home", Toast.LENGTH_SHORT).show();
default:
return super.onOptionsItemSelected(item);
}
}
}
在onCreate()中通过getSupportActionBar()获得ActionBar的引用,并且开始设置其标题属性。副标题是可选项,但如果未提供标题,ActionBar将显示Activity清单中提供android:label字符串。
使用setDisplayHomeAsUpEnabled()方法,可以根据需要激活可选的Up箭头。该箭头用于向回导航至父Activity,通常在顶层Activity不启用。Up按钮的行为由应用程序定义。用户单击该按钮将触发Activity的onOptionsItemSeleted()方法并包含android.R.id.home值。
1.自定义视图
ActionBar还支持自定义视图。设置自定义视图时,该视图显示在标题和操作按钮之间。如果视图布局填满屏幕宽度,它将隐藏标题文本。自定义视图不能重叠已启用的Up按钮。以下代码显示了在ActionBar中启用自定义视图的Acticity。
ActionBar的自定义视图
public class SupportActionActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayShowCustomEnabled(true);
//显示图片取代标题
ImageView imageView = new ImageView(this);
imageView.setImageResource(R.drawable.ic_launcher);
imageView.setScaleType(ImageView.ScaleType.CENTER);
ActionBar.LayoutParams lp = new ActionBar.LayoutParams(
ActionBar.LayoutParams.MATCH_PARENT,
ActionBar.LayoutParams.MATCH_PARENT);
actionBar.setCustomView(imageView, lp);
}
}
这会将应用程序启动图标的图片放入ActionBar,该位置之前显示的是标题文本,产生的结果如下图所示。
2. Toolbar
当应用程序的设计要求更多德尔控制ActionBar的放置和顺序时,可以使用Toolbar代替。ToolBar能代替标准的Actionbar,因此必须对从窗口装饰中移除ActionBar的Activity应用主题。
ToolBar的Activity清单
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.androidrecipes.actionbar"
android:versionCode="1"
android:versionName="1.0">
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
<activity
android:name=".SupportToolbarActivity"
android:label="@string/label_toolbar"
android:theme="@style/AppToolbarTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
res/values/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Toolbar代替标准的Action Bar,
因此必须对从窗口装饰中移除Action Bar的Activity应用主题 -->
<style name="AppToolbarTheme" parent="@style/Theme.AppCompat.Light.NoActionBar">
<!-- 提供装饰主题颜色 -->
<item name="colorPrimary">@color/primaryGreen</item>
<item name="colorPrimaryDark">@color/darkGreen</item>
<item name="colorAccent">@color/accentGreen</item>
</style>
</resources>
在本例中,样式主题继承Theme.AppCompat.Light.NoActionBar,后者禁用窗口中的默认ActionBar;我们将使用自己的Toolbar代替它。以下代码显示了ToolbarActivity的布局。
res/layout/activity_toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<!-- 此处加入其他的应用程序视图内容 -->
</LinearLayout>
Toolbar小部件必须位于视图层次结构中的某个位置,通常是在视图的顶部。Toolbar不会自动接收主题样式,因此需要将背景色设置为当前激活主题中的colorPrimary属性。我们还必须向Toolbar传递主题属性,Toolbar使用此属性样式化它创建的扩展资源,如操作按钮和弹出列表菜单。ThemeOverlay.AppCompat.Dark.ActionBar是特殊的“重叠”主题的一部分,AppCompat提供该类以仅应用ActionBar或Toolbar所需的元素样式化其内容组件。
以下代码显示了将上述内容结合在一起的Activity代码。
ToolBarActivity
public class SupportToolbarActivity extends ActionBarActivity {
private Toolbar mToolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_toolbar);
//必须将Toolbar的所在位置告诉Activity
mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
/*
* 使用Toolbar,必须在onCreate()之后设置标题文本;
* 否则默认标签将覆盖我们的设置
*/
//设置标题文本
mToolbar.setTitle("Android Recipes");
//设置副标题文本
mToolbar.setSubtitle("Toolbar Recipes");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.support, menu);
return true;
}
}
在onCreate()内部,我们负责通过setSupportActionBar()向Activity传递布局内Toolbar的引用。尽管该方法的命名很含糊,但它确实需要ToolBar作为参数。这就可以使Activity向视图应用选项菜单和其他特定项。
在使用Toolbar时,我们必须对前一个示例进行移除修改。Activity实现在OnCreate()完成后设置Toolbar实例的标题值。这意味着在onCreate()中设置的任何标题将重置为清单的android:label值。为抵消这种行为,我们必须在onPostCreate()中进行修改以使改动得以保持。
如果运行此Activity,其外观如图(带有Up按钮的标准Action Bar)所示。本章后面将给出不同UI范例如何倾向于使用Toolbar而非顶层ActionBar的示例。