【Kotlin】ToolBarに戻るボタンをつける + Navigation

# はじめに
簡単そうなのに結構時間がかかったのでメモ。
「戻るボタンをつける」系の過去記事は、ToolBarでなくActionBarを使っていたり、Navigationを使っていなかったりする記事が多いので注意が必要です（実装方法がだいぶ違います）。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112818/569f8e33-2483-0af1-4ff3-74909a046738.png" width="400"/>

## 環境
* macOS: 10.14.1
* Android Studio: 3.4
* kotlin: 1.3.21
* Support Library: AndroidX

# Toolbarについておさらい
* Android 5.0 (Lollipop)で従来のActionBarの代わりに追加されたコンポーネント
* マテリアルデザインの導入に合わせて、ヘッダーまわりの考え方を整理する中で生まれた
* ActionBarに比べて柔軟性が高く、他のビューのスクロールに合わせてアニメーションしやすい

比べてみるとToolBarではバー下の影がなくなっているのがわかる。
<img width="400" alt="スクリーンショット 2019-05-30 2.11.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112818/0e7147b4-b400-c1e7-2ad5-b324c0247f32.png">
<img width="400" alt="スクリーンショット 2019-05-30 2.10.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112818/718e717d-5479-c82e-7134-316d93c6c0d2.png">



# 戻るボタンをつけるまでの手順
MainActivityと、そこに乗せるFragment、さらに遷移先のFragmentをあらかじめ用意しておく。

## Navigation Graphを作成する
`res`フォルダ配下で新たに`navigation`フォルダを作成し、その中で遷移グラフを作成する。
（Android Studio3.4では、`Preferences`から`Navigation Editor`にチェックを入れる工程は不要）
<img width="641" alt="スクリーンショット 2019-05-30 1.43.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112818/a06b9a8f-96a2-af4f-3d4d-2415ae673f14.png">

```xml:navigation_graph.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/navigation_graph"
    app:startDestination="@id/pagerFragment">

    <fragment
        android:id="@+id/pagerFragment"
        android:name="com.example.my_app.ui.PagerFragment"
        android:label="my_app">
        <action
            android:id="@+id/action_to_detail"
            app:destination="@id/detailFragment"/>
    </fragment>
    <fragment
        android:id="@+id/detailFragment"
        android:name="com.example.my_app.ui.DetailFragment"
        android:label="DetailFragment"/>
</navigation>
```

※詳細な手順は下記記事あたりを参考にしてください。
[Android 10分で作る、Navigationによる画面遷移 - Qiita](https://qiita.com/tktktks10/items/7df56b4795d907a4cd31)

## activity_main.xmlの設定

`activity_main.xml`にはToolbarを設置し、先程作成した`navigation_graph`を`NavHostFragment`に設定する。

```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

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

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"/>

        <fragment
            android:id="@+id/nav_host_fragment"
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            android:name="androidx.navigation.fragment.NavHostFragment"
            app:navGraph="@navigation/navigation_graph"
            app:defaultNavHost="true"/>

    </LinearLayout>
</layout>
```

`app:defaultNavHost`をtrueにしておくとBackボタン（端末左下のボタン）で戻れるようになる。

## ActionBarを無効にする
ActionBarがデフォルトでセットされているので、それを無効にしないとToolBarは表示されず、下記のようなエラーに苦しめられることになる。

```
This Activity already has an action bar supplied by the window decor. Do not request Window.FEATURE_ACTION_BAR and set windowActionBar to false in your theme to use a Toolbar instead.
```

`styles.xml`のAppThemeのparentを、`Theme.AppCompat.Light.NoActionBar`に設定することでActionBarを無効化することができる。また、ToolBarの色のカスタマイズもここで一緒に行える。

```xml

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- ToolBarの背景色 -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <!-- ToolBarのタイトルテキスト色 -->
        <item name="android:textColorPrimary">@color/white</item>
    </style>
</resources>
```

## 戻るボタンを表示させる
MainActivityに下記のように記述することで、遷移先で戻るボタンが表示されるようになる。

```kotlin:MainActivity.kt
class MainActivity : AppCompatActivity() {

    private val binding by lazy {
        DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setSupportActionBar(binding.toolbar)

        val navController = findNavController(R.id.nav_host_fragment)
        val appBarConfiguration = AppBarConfiguration(navController.graph)
        setupActionBarWithNavController(navController, appBarConfiguration)
    }

    override fun onSupportNavigateUp()
            = findNavController(R.id.nav_host_fragment).navigateUp()
}
```

`setSupportActionBar`でToolBarをActionBarとしてセットする。
`appBarConfiguration`に遷移グラフを渡すことで、戻るボタンの表示/非表示などをいい感じに管理してくれるようになる。

`setupActionBarWithNavController()`を呼ぶことで戻るボタンが表示されるようになるのだが、これだけではボタンを押しても何も反応してくれない。
`onSupportNavigateUp()`をオーバーライドすることで初めて、戻るボタンが機能するようになる。


# 参考
 [Android公式 - Update UI components with NavigationUI](https://developer.android.com/guide/navigation/navigation-ui) 
[Navigation Architecture Componentを試してみる - Qiita](https://qiita.com/jimmysharp/items/06f3157152fbc4cd5113)
[MaterialDesignことはじめ ActionBar編 - Qiita](https://qiita.com/androhi/items/f12b566730d9f951b8ec)
[AndroidのToolBar（新しいActionBar）メモ - Qiita](https://qiita.com/kobakei/items/f17019f8b0a88c8e57f4)
[ToolBar(ActionBar)を自前で作りたいときに遭遇するエラーへの対処 - Qiita](https://qiita.com/tanukiti1987/items/e556ed9ef3aca76a49e9)
[Android 10分で作る、Navigationによる画面遷移 - Qiita](https://qiita.com/tktktks10/items/7df56b4795d907a4cd31)
[【Android】Google IO 2018で新発表された navigation についての詳細レポート - DMM inside](https://inside.dmm.com/entry/2018/05/25/android-navigation)