MaterialDesignことはじめ ActionBar編


自分が関わるアプリにMaterialDesignを取り込んでいくために、試行錯誤したことをまとめます。（たぶん後で加筆すると思います。）

## MaterialDesignにおけるActionBar

大きく分けると2種類あります。正確には本来のActionBarと、ActionBarの機能を持たせた新たなWidgetのToolBarの2つです。
左図がActionBarで右図がToolBarです。デフォルトでの影の付き方が異なるだけで、あとはほとんど一緒です。

![actionbar_sample.png](https://qiita-image-store.s3.amazonaws.com/0/4706/6ccf7a6f-bf6e-a06f-b07a-a51e8ad145e9.png "actionbar_sample.png") ![toolbar_sample.png](https://qiita-image-store.s3.amazonaws.com/0/4706/b96357af-a8a2-33d9-537a-ae4efffc18fa.png "toolbar_sample.png")

コードだと以下の通りです。（ここではAndroid4.4での実装を例にしてますので、appcompat-v7を使用してます。）

**共通**

```
dependencies {
    compile 'com.android.support:appcompat-v7:21.0.+'
}
```

**ActinoBar**

```xml:style.xml
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    </style>
```

```
<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"
    android:paddingLeft="16dp"
    tools:context=".MainActivity">

    <TextView android:text="@string/hello_world" 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>
```

```java:MainActivity.java
public class MainActivity extends ActionBarActivity {

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

**ToolBar**

```xml:style.xml
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    </style>
```

```xml:activity_main.xml
<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=".MainActivity">

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

    <TextView android:text="@string/hello_world" android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/sample_toolbar"
        android:layout_marginTop="16dp"
        android:layout_marginLeft="16dp"/>

</RelativeLayout>
```

```java:MainActivity.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.sample_toolbar);
        setSupportActionBar(toolbar);
    }
```

### ActionBarの実装で気をつけること

1. いくらstyleやxmlでActionBarについて設定したとしても、最終的には作成するActivityクラスにActionBarActivityを継承させないと表示されませんでした。
2. 影をつけたくないときは、`getSupportActionBar().setElevation(0)`すればいいっぽい。

### ToolBarの実装で気をつけること

1. styleで必ず`NoActionBar`のテーマを使う
2. あくまでViewなのでレイアウトに気をつける
3. 必ずonCreateで`setSupportActionBar()`する

## ナビゲーション・ドロワーを追加する

### ActionBarでの実装の場合

ポイントは2点ありました。

1. support.v7.app.ActionBarDrawerToggleクラスを使う
  - 3本線と矢印の画像やアニメーションなども自動でつく
2. ナビゲーション部分のレイアウトをStart側に寄せる指定をする
  - 指定しないと実行は出来るけどクラッシュしました

![ab_drawerlayout.png](https://qiita-image-store.s3.amazonaws.com/0/4706/61feda39-3a61-0594-3a40-ad5cf6f14990.png "ab_drawerlayout.png")  ![tb_drawerlayout.png](https://qiita-image-store.s3.amazonaws.com/0/4706/57c32ad0-8a6f-655b-c22d-c953be280f75.png "tb_drawerlayout.png")

```xml:activity_main.xml
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- content -->
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:text="@string/hello_world"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </RelativeLayout>

    <!-- nav drawer:ここをstart側に寄せる -->
    <LinearLayout
        android:layout_gravity="start"
        android:layout_width="280dp"
        android:layout_height="match_parent"
        android:background="#fff">

        <ListView
            android:id="@+id/listview"
            android:layout_width="wrap_content"
            android:layout_height="match_parent" />

    </LinearLayout>

</android.support.v4.widget.DrawerLayout>
```

```java:MainActivity.java
public class MainActivity extends ActionBarActivity {

    private DrawerLayout vDrawerLayout;
    private ActionBarDrawerToggle vDrawerToggle;
    private ListView vListView;

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

        vDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        initDrawer();

        vListView = (ListView) findViewById(R.id.listview);
        vListView.setAdapter(new ArrayAdapter<String>(
                this, android.R.layout.simple_list_item_1, new String[]{"menu 1", "menu 2", "menu 3"}));
    }

    private void initDrawer() {
        // （3本線の）切り替えボタンの生成
        vDrawerToggle = new ActionBarDrawerToggle(this, vDrawerLayout, R.string.app_name, R.string.app_name);
        vDrawerToggle.setDrawerIndicatorEnabled(true);
        vDrawerLayout.setDrawerListener(vDrawerToggle);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
    }

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

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return vDrawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        vDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        vDrawerToggle.onConfigurationChanged(newConfig);
    }
}
```

### Toolbarでの実装の場合

やることはActionBarの時と同じですが、Toolbarをコンテンツ領域のwidgetとしてLayoutファイルに記述するため、Navigation部分が覆いかぶさってきます。

![tb_dl.png](https://qiita-image-store.s3.amazonaws.com/0/4706/f68b31e2-47b8-ae95-d0d4-1dfc541eee4a.png "tb_dl.png")  ![tb_dl2.png](https://qiita-image-store.s3.amazonaws.com/0/4706/11f75c60-bb82-5ea0-2d68-467314d1e833.png "tb_dl2.png")

```xml:activity_main.xml
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- content -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

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

        <TextView
            android:text="@string/hello_world"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </LinearLayout>

    <!-- nav drawer -->
    <LinearLayout
        android:layout_gravity="start"
        android:layout_width="280dp"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="#fff">

        <ListView
            android:id="@+id/listview"
            android:layout_width="wrap_content"
            android:layout_height="match_parent" />

    </LinearLayout>

</android.support.v4.widget.DrawerLayout>
```

```java:MainActivity.java
public class MainActivity extends ActionBarActivity {

    private DrawerLayout vDrawerLayout;
    private ActionBarDrawerToggle vDrawerToggle;
    private ListView vListView;

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

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        vDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        initDrawer();

        vListView = (ListView) findViewById(R.id.listview);
        vListView.setAdapter(new ArrayAdapter<String>(
                this, android.R.layout.simple_list_item_1, new String[]{"menu 1", "menu 2", "menu 3"}));
    }

    private void initDrawer() {
        vDrawerToggle = new ActionBarDrawerToggle(this, vDrawerLayout, R.string.app_name, R.string.app_name);
        vDrawerToggle.setDrawerIndicatorEnabled(true);
        vDrawerLayout.setDrawerListener(vDrawerToggle);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
    }

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

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }

        return vDrawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        vDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        vDrawerToggle.onConfigurationChanged(newConfig);
    }
}
```

### どちらが良いか？

[公式のガイドライン](http://www.google.com/design/spec/patterns/navigation-drawer.html)によると、Toolbarを使う形にしろと書いてあります。
けど、Google製アプリでもActionBarを使ってるものもあるし、今はまだケースバイケースかなーと感じます。

## 参考にしたサイト

- [AppCompat v21 — Material Design for Pre-Lollipop Devices!](http://android-developers.blogspot.jp/2014/10/appcompat-v21-material-design-for-pre.html)
- [Maintaining Compatibility](http://developer.android.com/training/material/compatibility.html)
- [Support Library Features](http://developer.android.com/tools/support-library/features.html#v7-appcompat)