替换操作栏

概述

Toolbar 最常见的用途之一是将默认操作栏替换为自定义 Toolbar(创建新的 Android 项目时,它使用默认操作栏)。 由于 Toolbar 能够向活动 UI 的应用栏部分添加品牌徽标、标题、菜单项、导航按钮,甚至自定义视图,这会为默认操作栏提供重大升级。

若要将应用的默认操作栏替换为 Toolbar

  1. 创建新的自定义主题并修改应用的属性,使其使用此新主题。

  2. 禁用自定义主题中的 windowActionBar 特性并启用 windowNoTitle 特性。

  3. 定义 Toolbar 的布局。

  4. 在活动的 Main.axml 布局文件中加入 Toolbar 布局。

  5. 将代码添加到活动的 OnCreate 方法中,以查找 Toolbar 并调用 SetActionBar 以安装 ToolBar 作为操作栏。

以下部分详细介绍了此过程。 创建了一个简单的应用,其操作栏替换为自定义的 Toolbar

启动应用项目

创建名为 ToolbarFun 的新 Android 项目(请参阅 Hello, Android 了解有关创建新 Android 项目的详细信息)。 创建此项目后,将目标和最低 Android API 级别设置为 Android 5.0(API 级别 21 - Lollipop) 或更高版本。 有关设置 Android 版本级别的详细信息,请参阅了解 Android API 级别。 生成并运行应用后,会显示默认操作栏,如以下屏幕截图所示:

默认操作栏的屏幕截图

创建自定义主题

打开 Resources/values 目录,并创建名为 styles.xml 的新文件。 用以下 XML 替代其内容:

<?xml version="1.0" encoding="utf-8" ?>
<resources>
  <style name="MyTheme" parent="@android:style/Theme.Material.Light.DarkActionBar">
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowActionBar">false</item>
    <item name="android:colorPrimary">#5A8622</item>
  </style>
</resources>

此 XML 定义了一个名为 MyTheme 的新自定义主题,该主题基于 Lollipop 中的 Theme.Material.Light.DarkActionBar 主题。 windowNoTitle 特性设置为 true 以隐藏标题栏:

<item name="android:windowNoTitle">true</item>

若要显示自定义工具栏,必须禁用默认的 ActionBar

<item name="android:windowActionBar">false</item>

橄榄绿的 colorPrimary 设置用于工具栏的背景色:

<item name="android:colorPrimary">#5A8622</item>

应用自定义主题

编辑 Properties/AndroidManifest.xml 并将以下 android:theme 特性添加到 <application> 元素,以便应用使用 MyTheme 自定义主题:

<application android:label="@string/app_name" android:theme="@style/MyTheme"></application>

有关将自定义主题应用于应用的详细信息,请参阅使用自定义主题

定义工具栏布局

Resources/layout 目录中,创建名为 toolbar.xml 的新文件。 用以下 XML 替代其内容:

<?xml version="1.0" encoding="utf-8"?>
<Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?android:attr/actionBarSize"
    android:background="?android:attr/colorPrimary"
    android:theme="@android:style/ThemeOverlay.Material.Dark.ActionBar"/>

此 XML 定义了替换默认操作栏的自定义 ToolbarToolbar 的最小高度设置为其替换的操作栏的大小:

android:minHeight="?android:attr/actionBarSize"

Toolbar 的背景色设置为前面在 styles.xml 中定义的橄榄绿色:

android:background="?android:attr/colorPrimary"

从 Lollipop 开始,android:theme 特性可用于设置单个视图的样式。 Lollipop 中引入的 ThemeOverlay.Material 主题使覆盖默认 Theme.Material 主题变为可能,重写相关特性,使它们变为浅色或深色。 在此示例中,Toolbar 使用深色主题,使其内容以浅色显示:

android:theme="@android:style/ThemeOverlay.Material.Dark.ActionBar"

此设置用于使菜单项与深色背景色形成鲜明对比。

加入工具栏布局

编辑布局文件 Resources/layout/Main.axml 并将其内容替换为以下 XML:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <include
        android:id="@+id/toolbar"
        layout="@layout/toolbar" />
</RelativeLayout>

此布局包含 toolbar.xml 中定义的 Toolbar,并使用 RelativeLayout 指定 Toolbar 放置在 UI 顶部(按钮上方)。

查找并激活工具栏

编辑 MainActivity.cs 并添加以下 using 语句:

using Android.Views;

此外,将以下代码行添加到 OnCreate 方法的末尾:

var toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
SetActionBar(toolbar);
ActionBar.Title = "My Toolbar";

此代码会查找 Toolbar 并调用 SetActionBar,以便 Toolbar 对默认操作栏特征执行操作。 工具栏的标题更改为“我的工具栏”。 如本代码示例所示,ToolBar 可以直接作为操作栏引用。 编译并运行此应用 – 会显示自定义的 Toolbar 而不是默认操作栏:

使用绿色配色方案的自定义工具栏的屏幕截图

请注意,Toolbar 的样式独立于应用于应用的其余部分的 Theme.Material.Light.DarkActionBar 主题。

如果在运行应用时发生异常,请参阅下面的故障排除部分。

添加菜单项

在本部分中,菜单将添加到 ToolbarToolBar 的右上角区域为菜单项保留 – 每个菜单项(也称为操作项)都可以在当前活动中执行操作,也可以代表整个应用执行操作。

若要将菜单添加到 Toolbar

  1. 将菜单图标(如果需要)添加到应用项目的 mipmap- 文件夹。 Google 在“材料图标”页上提供了一组免费菜单图标。

  2. 通过在 Resources/menu 下添加新菜单资源文件来定义菜单项的内容。

  3. 实现活动的 OnCreateOptionsMenu 方法 – 此方法会扩充菜单项。

  4. 实现活动的 OnOptionsItemSelected 方法 – 此方法会在菜单项被点击时执行操作。

以下部分通过向自定义的 Toolbar 添加编辑保存菜单项来详细演示此过程。

安装菜单图标

继续操作 ToolbarFun 示例应用,将菜单图标添加到应用项目。 下载工具栏图标,解压缩,将提取的 mipmap- 文件夹的内容复制到 ToolbarFun/Resources 下的项目 mipmap- 文件夹,然后在项目中加入每个添加的图标文件。

定义菜单资源

Resources 下创建新的 menu 子目录。 在 menu 子目录中,创建一个名为 top_menus.xml 的新菜单资源文件,并将其内容替换为以下 XML:

<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
  <item
       android:id="@+id/menu_edit"
       android:icon="@mipmap/ic_action_content_create"
       android:showAsAction="ifRoom"
       android:title="Edit" />
  <item
       android:id="@+id/menu_save"
       android:icon="@mipmap/ic_action_content_save"
       android:showAsAction="ifRoom"
       android:title="Save" />
  <item
       android:id="@+id/menu_preferences"
       android:showAsAction="never"
       android:title="Preferences" />
</menu>

此 XML 会创建三个菜单项:

  • 使用 ic_action_content_create.png 图标(铅笔)的编辑菜单项。

  • 使用 ic_action_content_save.png 图标(磁盘)的保存菜单项。

  • 没有图标的首选项菜单项。

编辑保存菜单项的 showAsAction 特性设置为 ifRoom – 如果有足够的空间来显示这些菜单项,则会导致它们显示在 Toolbar 中。 首选项菜单项将 showAsAction 设置为 never – 这会导致首选项菜单显示在溢出菜单中(垂直三点)。

实现 OnCreateOptionsMenu

将以下方法添加到 MainActivity.cs

public override bool OnCreateOptionsMenu(IMenu menu)
{
    MenuInflater.Inflate(Resource.Menu.top_menus, menu);
    return base.OnCreateOptionsMenu(menu);
}

Android 会调用 OnCreateOptionsMenu 方法,以便应用可以为活动指定菜单资源。 在此方法中,top_menus.xml 资源会扩充到传递的 menu 中。 此代码会导致新的编辑保存首选项菜单项显示在 Toolbar 中。

实现 OnOptionsItemSelected

将以下方法添加到 MainActivity.cs

public override bool OnOptionsItemSelected(IMenuItem item)
{
    Toast.MakeText(this, "Action selected: " + item.TitleFormatted,
        ToastLength.Short).Show();
    return base.OnOptionsItemSelected(item);
}

当用户点击菜单项时,Android 会调用 OnOptionsItemSelected 方法并传入所选的菜单项。 在此示例中,该实现只显示了一个 toast 来指示哪个菜单项被点击。

生成并运行 ToolbarFun 以查看工具栏中的新菜单项。 现在 Toolbar 会显示三个菜单图标,如以下屏幕截图所示:

说明“编辑”、“保存”和“溢出”菜单项的位置的关系图

当用户点击编辑菜单项时,将显示一个 toast 以指示调用了 OnOptionsItemSelected 方法:

点击“编辑项”时显示的 Toast 屏幕截图

当用户点击溢出菜单时,将显示首选项菜单项。 通常应将不太常见的操作放在溢出菜单中 – 此示例为首选项使用溢出菜单,因为它不如编辑保存那样常用:

溢出菜单中显示的“首选项”菜单项的屏幕截图

有关 Android 菜单的详细信息,请参阅 Android 开发人员菜单主题。

疑难解答

以下提示有助于调试在将操作栏替换为工具栏时可能发生的问题。

活动已有操作栏

如果应用未正确配置为使用自定义主题,如应用自定义主题中所述,则在运行应用时可能会出现以下异常:

未使用自定义主题时可能发生的错误

此外,可能会生成如下错误消息:Java.Lang.IllegalStateException: 此活动已具有窗口装饰提供的操作栏。

若要更正此错误,请验证自定义主题的 android:theme 特性是否已添加到 <application>(在 Properties/AndroidManifest.xml 中),如前面的应用自定义主题中所述。 此外,如果 Toolbar 布局或自定义主题未正确配置,则可能会导致此错误。