如何將 Android ActionBar 轉換到 Toolbar

Toolbar

ActionBar 已經在 Android 5.x(API Level 21) 之後被改為由 Toolbar 來取代。
Toolbar 是應用程式內容的一部份,是 ActionBar 的通用化,不像 ActionBar 是獨立於內容之外的,意思就是,Toolbar 會在你的 layout 檔中出現,你可以在 view 階層中任意配置。如果你想把 Toolbar 當成 ActionBar,可以使用 setActionBar() 方法來達成。
Toolbar 提供比 ActionBar 更多的功能,包含的項目有:
  • 導覽按鈕(navigation button):通常位於左邊,可以是向上箭頭、選單按鈕等。
  • 商標圖案(branded logo image)
  • 標題及子標題(title and subtitle)
  • 客製化的 view
  • 動作選單(action menu)
從一開始使用非官方的 ActionBarSherlock 換到官方的 ActionBarCompat,現在又要換到 Toolbar ,真是累人,不過,可以感覺得出來越來越容易使用。這篇文章的範例會先建立一個 ActionBarCompat 的專案,之後將它轉換成使用 Toolbar。

大概流程先簡述,首先就是 Theme 要換成 Material 的,接著就是把 ActionBar 換成 Toolbar ,最後就可客製化自己的 Toolbar。

ActionBar 專案

建立 ActionBar 專案的詳細內容可以先參考之前的文章:使用 Android ActionBarCompat 製作導覽列 (2),這裡我只會以很簡化的方式來說明。

首先,新建一個專案,這裡假設你想要讓 2.3.x (API Level 10)之後的裝置都能相容,Min SDK 就設為 10,並將 Target SDK 選到API 22(或至少21,也就是 Android 5.x 這樣才能用 Material theme),完成後,在預設的情況下(請確定 Eclipse ADT 有更新到最新版本),你的 MainActivity 會繼承 ActionBarActivity,而且使用的是 v7 版本(請看 import 的部份)。

現在你已經有一個使用 ActionBar 的專案了,如果要改變 ActionBar 的標題,可以在 onCreate() 方法中,寫兩行程式:
ActionBar actionBar = this.getSupportActionBar();
actionBar.setTitle("這是ActionBar標題");
看起來是:

轉換 Theme

Material Theme

先瞭解一下 Material Theme 可以設定哪些部份,看下圖: (圖片來源:https://developer.android.com/training/material/theme.html)

Material Design Palette (色版)

Google 已經定義了主要的 Material Desgin 色版,我們可以直接拿來用。首先把這些顏色資源檔加入專案中,你可以下載 daniellevass/android_material_design_colours.xml 已經建好的檔案。

另外,你可以在 material palette 這個網站預先看看自己選擇顏色的搭配結果。

我們總共要在 res/values 下建立 3 個檔案:
  • theme_material.xml 佈景檔
  • colors_material.xml 色版
  • colors_default.xml 預設顏色檔
theme_material.xml

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">

    <style name="MyMaterialTheme" parent="MyMaterialTheme.Base">
    </style>

    <!-- 各API通用的基底theme -->
    <style name="MyMaterialTheme.Base" parent="Theme.AppCompat">
        <item name="android:windowNoTitle">true</item>
        <!-- 不需要 ActionBar 了,因為改用Toolbar -->
        <item name="windowActionBar">false</item>
        <!-- 主要顏色 -->
        <item name="colorPrimary">@color/color_primary</item>
        <!-- 狀態欄背景色 -->
        <item name="colorPrimaryDark">@color/color_primaryDark</item>
        <item name="colorAccent">@color/color_accent</item>
        <!-- 其他可用項目 colorControlNormal, colorControlActivated, colorControlHighlight, colorSwitchThumbNormal -->
    </style>
</resources>
MyMaterialTheme.Base 必須繼承 Theme.AppCompat 或屬於它的子元素,這是因為必須保持相容性。如果沒有相容性問題,而且是 min SDK 21 以上,可以直接用 Theme.Material。

我們實際上會使用的是 MyMaterialTheme ,它繼承 MyMaterialTheme.Base。
colors_material.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--reds-->
    <color name="md_red_50">#FFEBEE</color>
    <color name="md_red_100">#FFCDD2</color>
    <color name="md_red_200">#EF9A9A</color>
    <color name="md_red_300">#E57373</color>
    <color name="md_red_400">#EF5350</color>
    <color name="md_red_500">#F44336</color>
    <color name="md_red_600">#E53935</color>
    <color name="md_red_700">#D32F2F</color>
    <color name="md_red_800">#C62828</color>
    <color name="md_red_900">#B71C1C</color>
    <color name="md_red_A100">#FF8A80</color>
    <color name="md_red_A200">#FF5252</color>
    <color name="md_red_A400">#FF1744</color>
    <color name="md_red_A700">#D50000</color>

    <!--blue-->
    <color name="md_blue_50">#E3F2FD</color>
    <color name="md_blue_100">#BBDEFB</color>
    <color name="md_blue_200">#90CAF9</color>
    <color name="md_blue_300">#64B5F6</color>
    <color name="md_blue_400">#42A5F5</color>
    <color name="md_blue_500">#2196F3</color>
    <color name="md_blue_600">#1E88E5</color>
    <color name="md_blue_700">#1976D2</color>
    <color name="md_blue_800">#1565C0</color>
    <color name="md_blue_900">#0D47A1</color>
    <color name="md_blue_A100">#82B1FF</color>
    <color name="md_blue_A200">#448AFF</color>
    <color name="md_blue_A400">#2979FF</color>
    <color name="md_blue_A700">#2962FF</color>
</resources>
這裡只用了兩個顏色,其他顏色自行加入。
colors_default.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="color_primary">@color/md_red_500</color>
    <color name="color_primaryDark">@color/md_red_700</color>
    <color name="color_accent">@color/md_blue_500</color>
    <color name="color_primaryText">@android:color/white</color>
</resources>
colors_default 的用意是,方便有用到相同顏色的 view,當要修改顏色時,只要在一個地方改就可以了。

指定新的 Theme

打開 AndroidManifest.xml,將 application 中原本的 theme,換成 MyMaterialTheme,結果大概會是這樣:
<application    
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/MyMaterialTheme" >
...
現在你可以執行了,不過會出錯,因為我們現在已經沒有 ActionBar 了,所以原本程式碼中的
actionBar.setTitle("這是ActionBar標題");
會出現無法指定標題的錯誤,必須刪掉。並且要使用 5.x 以上的模擬器或裝置來測試,在這個版本之前的系統,無法設定狀態列的顏色,所以你會看不到 colorPrimaryDark 所指定的顏色。

現在看起來:
看不到 ActionBar 了,接下來來加入 Toolbar。

轉換 ActionBar

在 res/layout 建立一個 toolbar.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toolbar"
    android:layout_height="wrap_content" 
    android:layout_width="match_parent"
    android:minHeight="?attr/actionBarSize"
    android:background="?attr/colorPrimary" />
在原本的 layout/main.xml 中,加入 toolbar:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.tonycube.demo.toolbardemo.MainActivity" >

    <include
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        layout="@layout/toolbar" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/toolbar"
        android:text="@string/hello_world" />

</RelativeLayout>
用 include 的方式把 toolbar 加進來。現在的 toolbar 可以很靈活的佈置,例如,你可以把它放在螢幕下面。

接著在 onCreate 中呼叫新的 initToolbar():
private void initToolbar() {
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
}
結果如下,右邊是調整 layout 把 toolbar 放在下面的樣子: 如果要換標題,必須先 getSupportActionBar 來取得新的 ActionBar 之後才能設定:
ActionBar actionbar = getSupportActionBar();
actionbar.setTitle("這是 Toolbar 標題");
結果:

參考資料

本文網址:http://blog.tonycube.com/2015/06/toolbar-demo-toolbar-actionbar-android-5.html
Tony Blog 撰寫,轉載時請註明出處及文章連結,謝謝 😀

5 則留言

  1. 你好,我在setSupportActionBar(toolbar);
    ActionBar actionbar = getSupportActionBar();這兩句出錯
    import的是
    android.support.v7.app.ActionBar;
    android.support.v7.widget.Toolbar;
    請問該怎麼解決呢?

    回覆刪除
    回覆
    1. 你的 MainActivity 有繼承v7版本的 ActionBarActivity 嗎?

      刪除
    2. 請問一下actionbaractivity使用時會出現刪除號是不是不建議使用了?

      刪除
    3. 是的,
      查了一下API (https://developer.android.com/reference/android/support/v7/app/ActionBarActivity.html)
      建議換成 AppCompatActivity

      刪除
  2. 請問 App Bar 又是怎麼一回事?? 花花丫~~

    回覆刪除

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。