【Kotlin】BottomNavigation（下タブ） + Navigationを試してみる

# はじめに
モダンなアプリでよく使われている印象のBottomNavigation。
AndroidStudioのテンプレートを使う簡単な方法もありますが、今回は勉強のために一から作ってみます。
コードはGithubに載せています。[GitHub - orimomo/bottom-navigation-test](https://github.com/orimomo/bottom-navigation-test)
![Jun-16-2019 19-23-30.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112818/bd1585a2-ab20-6dd0-03e0-9ceec90b9336.gif)

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

# 手順
## 依存関係の設定
以下を追加します。

```groovy:app/build.gradle
dependencies {
    // MaterialComponentsのBottomNavigationを使うため
    implementation "com.google.android.material:material:1.1.0-alpha06"

    // Navigationを使うため
    def nav_version = '2.0.0'
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
```

## BottomNavigationの実装
まずはBottomNavigationを動くようにします。

activity_mainにBottomNavigationの要素を追加します。

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

    <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/bottom_navigation"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:background="?android:attr/windowBackground"
            app:menu="@menu/bottom_navigation_menu"/>
</FrameLayout>
```

`android:background`の他にも`app:itemIconTint`や`app:itemTextColor`を指定することで見た目を変えることができます。

次は`app:menu`に設定しているファイルを作っていきます。
menuパッケージを追加し、その中に`bottom_navigation_menu`ファイルを追加します。

```xml:bottom_navigation_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
            android:id="@+id/navi_smile"
            android:icon="@drawable/ic_insert_emoticon_black_24dp"
            android:title="スマイル"/>
    <item
            android:id="@+id/navi_pets"
            android:icon="@drawable/ic_pets_black_24dp"
            android:title="ペット"/>
    <item
            android:id="@+id/navi_sun"
            android:icon="@drawable/ic_wb_sunny_black_24dp"
            android:title="太陽"/>
    <item
            android:id="@+id/navi_flight"
            android:icon="@drawable/ic_airplanemode_active_black_24dp"
            android:title="飛行機"/>
</menu>
```

`android:icon`に指定するリソースは、drawableパッケージに事前にVectorAssetとして作成したものを使っています。

ここでビルドするとBottomNavigationが表示され、タブの切り替えができるようになっていると思います。
<img width="323" alt="スクリーンショット 2019-06-16 18.55.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112818/d3b77d95-a118-e5da-86a2-bfe3f8c2da5b.png">

## Navigationの実装
BottomNavigationのボタンを押すとそれぞれに違うFragmentを表示するようにしたいと思います。
表示させるFragmentのlayoutファイルとclassファイルをそれぞれ4つ作っておきます。

```xml:fragment_1.xml
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/pink">

    <TextView
            android:id="@+id/textView1"
            android:text="Fragment1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
```

```Kotlin:Fragment1.kt
class Fragment1 : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        super.onCreateView(inflater, container, savedInstanceState)
        return  inflater.inflate(R.layout.fragment_1, container, false)
    }
}
```



activity_mainに以下を追加します。

```xml:activity_main.xml
<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:navGraph`に設定しているファイルを作ります。
navigationパッケージを追加し、その中にnavigation_graphファイルを追加します。


```xml:navigation_graph.xml
<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/navi_smile">

    <fragment android:id="@+id/navi_smile"
              android:name="com.example.bottom_navigation_test.Fragment1"
              android:label="Fragment1"/>

    <fragment android:id="@+id/navi_pets"
              android:name="com.example.bottom_navigation_test.Fragment2"
              android:label="Fragment2"/>

    <fragment android:id="@+id/navi_sun"
              android:name="com.example.bottom_navigation_test.Fragment3"
              android:label="Fragment3"/>

    <fragment android:id="@+id/navi_flight"
              android:name="com.example.bottom_navigation_test.Fragment4"
              android:label="Fragment4"/>
</navigation>
```

各Fragmentに設定するidは、先程bottom_navigation_menuファイルで指定したidと同じものを対応させて使う必要がある点に注意が必要です。

最後にMainActivityでBottomNavigationとNavigationを紐づけて完成です。

```kotlin:MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val navController = findNavController(R.id.nav_host_fragment)
        setupWithNavController(bottom_navigation, navController)
    }
}
```

# さいごに
リップル付きのBottomNavigationが思ったよりも簡単に実装できました◎
ただ今回の実装だとタブを切り替えるとFragmentも再生成されてしまうので、次回はFragmentの状態を保持できる実装を試してみたいと思います。

## 参考
[Bottom navigation - Material Design](https://material.io/design/components/bottom-navigation.html#usage)
[Getting Started - Material Components for Android](https://material.io/develop/android/docs/getting-started/)
[Navigation + BottomNavigationViewでFragmentの状態を残す – Kenji Abe – Medium](https://medium.com/@star_zero/navigation-bottomnavigationview%E3%81%A7fragment%E3%81%AE%E7%8A%B6%E6%85%8B%E3%82%92%E6%AE%8B%E3%81%99-46ae5a99dac2)
[BottomNavigationView と Navigationを一緒に使う - Qiita](https://qiita.com/superman9387/items/d373c8bddfe2243a49a7)