AndroidのToolBar（新しいActionBar）メモ

## 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内に書くスタイルの模様

```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ナビゲーションとかメニューとか）がそのまま使える

```java
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できる。

```java
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以降のみ反映されるのかも。

```xml: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. タイトルとサブタイトル
    * ロゴを使用する場合は使用しない方がいい
3. カスタムビュー（複数可）
4. メニュー

### ナビゲーションボタン

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

```java
    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ナビゲーションを使える。

```java: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を指定するのもお忘れなく

```xml: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>
```


### ロゴ・タイトル

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

```java
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

```xml
<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を呼ばない場合は、以下のようなコードでメニューのインフレート、クリックアクションのハンドリングができる

```java
// インフレート
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に

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

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

## タブ

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

代替案として、

* PagerTabStripを追加する
    * 見た目がいわゆるタブっぽくないので微妙かも
* Google公式サンプルのSlidingTabsBasicを使う
    * 見た目がそれっぽい。タブのカーソル（ハイライト部分）がViewPagerに合わせて一緒に動くなどすぐれもの
    * http://developer.android.com/intl/ja/samples/SlidingTabsBasic/index.html
* TabHostを使う
    * 参考：http://y-anz-m.blogspot.jp/2014/12/androidmaterial-design-tabhost-viewpager.html

などがあるみたい

~~タブを非推奨にするなら、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はそのままだと影が全く出ない。で、試した結果これがよさそう。

```xml
    <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"を指定してあげる。

## 参考

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

* http://android-developers.blogspot.jp/2014/10/appcompat-v21-material-design-for-pre.html
* https://developer.android.com/intl/ja/reference/android/support/v7/widget/Toolbar.html
* http://stackoverflow.com/questions/26450936/actionmode-with-toolbar-offsetting-content