AndroidのToolBar(新しいActionBar)メモ

  • 457
    Like
  • 0
    Comment

ToolBarとは?

Android 5.0 (Lollipop)と同時に追加されたActionBarの代替となるコンポーネント。
従来のActionBarに比べて、

  • カスタマイズしやすい
  • 他のビューのスクロールに合わせてアニメーションしやすい

などのメリットがあるらしい。
Android 5.0でマテリアルデザインが導入されたことでActionBar周りのUIガイドラインも微妙に変わっているようで、それに合わせてToolBarが追加された模様。

ちなみに、support library v7にも入ってるので、4.4以前の古いAndroidでもちゃんと使える。

基本的な使い方

Android 4.x時代のActionBarは、レイアウトXMLに明示的に書かないでActivityのthemeをTheme.AppCompat.Lightとかってしとけば勝手に表示されてた。
ToolBarは、これとは違って各自レイアウトXML内に書くスタイルの模様

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <!-- ここにToolBarを定義 -->
    <android.support.v7.widget.Toolbar
        android:id="@+id/tool_bar"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
        android:minHeight="?attr/actionBarSize"
        android:background="?attr/colorPrimary">
    </android.support.v7.widget.Toolbar>

    <!-- 以下、その他のビュー(省略) -->

</RelativeLayout>

そして、ActivityのonCreateで、以下のようにアクションバーとしてセットする。こうしとくと、これまで使ってたアクションバーの機能(upナビゲーションとかメニューとか)がそのまま使える

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // ツールバーをアクションバーとしてセット
        Toolbar toolbar = (Toolbar) findViewById(R.id.tool_bar);
        setSupportActionBar(toolbar);
    }
}

ちなみに、setSupportActionBarせずに、ただのビューとしてToolBarを使える。その場合はメニューが自動でinflateされないので、以下のようにプログラムでinflateできる。

toolbar.inflateMenu(R.menu.main);
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem menuItem) {
                int id = menuItem.getItemId();
                if (id == R.id.action_settings) {
                    Toast.makeText(MainActivity.this, "settings clicked 2", Toast.LENGTH_SHORT).show();
                    return true;
                }
                return false;
            }
        });

基本はsetSupportActionBarをすることになると思うが、ToolBarに独自の動きをさせたい場合などは後者の使い方になるかも

ToolBarのデザインをカスタマイズ

styles.xmlを編集する。

setSupportActionBarを呼ぶ場合は従来のActionBarみたいによしななスタイルになるが、呼ばない場合は背景やテキスト色などtoolbarStyleに色々定義する必要あり。

iOS7みたいにcolorPrimaryDarkでステータスバーの色を変更できるみたいだけど、KitKatだと反映されなかったのでLollipop以降のみ反映されるのかも。

styles.xml
<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

        <item name="colorPrimary">@android:color/white</item>
        <item name="colorPrimaryDark">@android:color/darker_gray</item>
        <item name="colorAccent">#ff0000</item>

        <!-- Toolbarのnavigation & overflow icon の色 -->
        <item name="colorControlNormal">@color/white</item>

        <!-- ActionModeを使うのに必要(後述) -->
        <item name="windowActionModeOverlay">true</item>

        <!-- Toolarのスタイル -->
        <item name="toolbarStyle">@style/MyApp.Toolbar</item>
    </style>

        <style name="MyApp.Toolbar" parent="Widget.AppCompat.Toolbar">
        <item name="android:background">@color/toolbar_bg</item>
        <item name="titleTextAppearance">@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse</item>
        <item name="subtitleTextAppearance">@style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle.Inverse</item>
    </style>

</resources>

ToolBar内の要素

ツールバーの中には、左から順に以下の要素が入る

  1. ナビゲーションボタン
  2. ロゴ
  3. タイトルとサブタイトル
    • ロゴを使用する場合は使用しない方がいい
  4. カスタムビュー(複数可)
  5. メニュー

ナビゲーションボタン

ActionBarにあったHome/Upナビゲーション関連のメソッドが大方ToolBarには存在しないので、ToolBarを単体で使う場合(setSupportActionBarしない場合)は、ToolBar$setNavigationIconを代わりに使う。

    toolbar.setNavigationIcon(R.drawable.ic_launcher);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "Navigation click", Toast.LENGTH_SHORT).show();
            }
        });

setSupportActionBar(ToolBar)を呼ぶ場合は、普通のActionBarのUpナビゲーションを使える。

DetailActivity.java
public class DetailActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);

        // ツールバーをアクションバーとして使う
        Toolbar toolbar = (Toolbar)findViewById(R.id.tool_bar);
        setSupportActionBar(toolbar);

        // UPナビゲーションを有効化する
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.detail, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        // いつものUPナビゲーションの処理
        switch (id) {
            case android.R.id.home:
                NavUtils.navigateUpFromSameTask(this);
                return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

AndroidManifest.xmlで、親のActivityを指定するのもお忘れなく

AndroidManifest.xml
        <activity
            android:name=".DetailActivity"
            android:label="@string/title_activity_detail" >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="com.exmaple.MasterActivity" />
        </activity>

ロゴ・タイトル

ロゴ、タイトル用のメソッドもある

toolbar.setLogo(R.drawable.ic_launcher);

toolbar.setTitle("This is title");

toolbar.setSubtitle("This is sub-title");

デザイン的には、

In modern Android UIs developers should lean more on a visually distinct color scheme for toolbars than on their application icon. The use of application icon plus title as a standard layout is discouraged on API 21 devices and newer.

とAPI referenceに書いてあるので、アイコン+テキストをバーの左に表示するUIは推奨されない。アイコンよりも色などでアプリの個性を出せとのこと。

ToolBarにカスタムビューを追加

レイアウトのXMLに以下のようにして子ビューを入れ子にすればOK

<android.support.v7.widget.Toolbar
        android:id="@+id/tool_bar"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:minHeight="?attr/actionBarSize"
        android:background="?attr/colorPrimary">

        <!-- ためしにスピナーを追加 -->
        <Spinner
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:entries="@array/spinner_values"
            android:id="@+id/spinner" />

</android.support.v7.widget.Toolbar>

メニュー

setSupportActionBarを呼ぶ場合

setSupportActionBarを呼んだ場合は、従来のActionBarと一緒なので省略
SearchViewなどのActionViewもそのまま使える

setSupportActionBarを呼ばない場合

setSupportActionBarを呼ばない場合は、以下のようなコードでメニューのインフレート、クリックアクションのハンドリングができる

// インフレート
toolbar.inflateMenu(R.menu.hoge);
// リスナーの登録
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
    @Override
    public boolean onMenuItemClick(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.foo:
                // do foo
                return true;
        }
        return true;
    }
});

ActionModeは?

(ActionMode = Gmailアプリでメールを長押しした時にアクションバーの色が変わるアレ)

ActionModeも使えるっぽい。
ただし、styles.xmlに

<item name="windowActionModeOverlay">true</item>

を追加しないとToolBarとActionBarが二重に表示されるので注意

タブ

ICS以降でよく使われていたActionBarのタブ関連APIが軒並み非推奨になってる

代替案として、

などがあるみたい

タブを非推奨にするなら、SlidingTabsBasicをSupport Libraryに入れといて欲しい。。。

(追記)
TabLayoutがdesign libraryに追加されたので多分これを使うのが正しい
http://developer.android.com/intl/ja/reference/android/support/design/widget/TabLayout.html

ドロワー

マテリアルデザインのガイドラインでは、「ドロワーはアクションバーの上にかぶる」のが正しいとされているので、DrawerLayoutの中にToolbarを置くことになる。

参考: http://www.riaxdnp.jp/?p=6965

ツールバーに影を付けたい

昔のActionBarは勝手にバーの下部に影が出てたけど、Toolbarはそのままだと影が全く出ない。で、試した結果これがよさそう。

    <android.support.v7.widget.Toolbar
        android:id="@+id/tool_bar"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:elevation="4dp"
        android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
        android:minHeight="?attr/actionBarSize"
        android:background="?attr/colorPrimary">
    </android.support.v7.widget.Toolbar>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:foreground="?android:windowContentOverlay"
        android:layout_below="@+id/tool_bar">
    </FrameLayout> 

Toolbatのandroid:elevation="4dp"は、Lollipop移行でしか影が出ないので、
Pre-Lollipop用に、コンテンツ部分をFrameLayoutにまとめてandroid:foreground="?android:windowContentOverlay"を指定してあげる。

参考

大体このへんの記事のまとめです