NavigationDrawer（サイドメニュー）を実装する

# はじめに
KotlinでNavigationDrawerを実装する方法を忘れないために、メモがてら書いています。
コードを簡潔にするため、バインディングは使用していません。

# 環境
- Android Studio 4.1.1
- kotlin 1.4.10

# 事前準備
### 1. 画面の作成
各画面はフラグメントで実装するため、MainActivity以外に今回は

- **HomeFragment**
- **ProfileFragment** 
- **SettingsFragment**

を用意する。


### 2. Navigation Graphの作成
画面遷移を管理するNavigationファイルを作成する。
**res -> New -> Android Resource File**

![スクリーンショット 2021-02-09 15.13.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663839/70b215a8-6d80-d6ab-02f4-fd6be3161c4f.png)

最初に作成した3つのフラグメントを追記する。
GUIからでもフラグメントを追加可能。

```xml:navigation.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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/navigation"
    app:startDestination="@id/homeFragment">

    <fragment
        android:id="@+id/homeFragment"
        android:name="com.example.drawerexample.HomeFragment"
        android:label="fragment_home"
        tools:layout="@layout/fragment_home" />
    <fragment
        android:id="@+id/profileFragment"
        android:name="com.example.drawerexample.ProfileFragment"
        android:label="fragment_profile"
        tools:layout="@layout/fragment_profile" />
    <fragment
        android:id="@+id/settingsFragment"
        android:name="com.example.drawerexample.SettingsFragment"
        android:label="fragment_settings"
        tools:layout="@layout/fragment_settings" />
</navigation>
```

# 実装手順
### 1. 依存関係の追加

```gradle:build.gradle
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.0'
```

### 2. メニューのレイアウトファイル作成
**res -> New -> Android Resource File**

![スクリーンショット 2021-02-06 13.59.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663839/874f6bd2-40c2-c81e-818b-0c513fe9215e.png)


メニューに表示するアイテムを定義。
android:idは`navigation.xml`で定義している各フラグメントのidと同じ必要があるので注意。
アイテムにアイコンを表示する場合は、`android:icon`を定義する。

```xml:navdrawer_menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/profileFragment"
        android:title="プロフィール" />
    <item
        android:id="@+id/settingsFragment"
        android:title="設定" />
</menu>
```

### 3. DrawerLayoutを定義する
まず、ナビゲーションドロワーを追加するため、`DrawerLayout`をルートビューとして宣言する。
既存のfragmentを`NavHostFragment`に変更する。
次に、`</LinearLayout>`の下にナビゲーションドロワーのビューを表示する用の`NavigationView`を追加する。

```xml:activity_main.xml
<androidx.drawerlayout.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

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

        <fragment
            android:id="@+id/navHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"

            android:name="androidx.navigation.fragment.NavHostFragment"
            app:defaultNavHost="true"
            app:navGraph="@navigation/navigation" />

    </LinearLayout>

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/navView"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:menu="@menu/navdrawer_menu" />

</androidx.drawerlayout.widget.DrawerLayout>
```

**android:layout_gravity：どの方向からスワイプすることでメニューが表示されるかを設定する**
**app:menu：ドロワーメニューのレイアウトファイル(XML)を設定する**

この時点で左から右にスワイプするとメニューが表示されるが、各アイテムをタップしても対象の画面に遷移されないため、`MainActivity.kt`の`onCreate()`に以下のコードを追加。

```kotlin:MainActivity.kt
val navView: NavigationView = findViewById(R.id.navView)
val navController = this.findNavController(R.id.navHostFragment)

NavigationUI.setupWithNavController(navView, navController)
```

### 4. ドロワーボタンを追加する

このままではスワイプでしか表示することができないので、ドロワーを表示するためのボタンを設定する。

##### 1. DrawerLayout変数を定義
```kotlin:MainActivity.kt
private lateinit var drawerLayout: DrawerLayout
```

##### 2. DrawerLayout変数を初期化
`onCreate()`メソッド内で、drawerLayoutを初期化する。

```kotlin:MainActivity.kt
drawerLayout = findViewById(R.id.drawerLayout)
```

##### 3. DrawerLayoutをsetupActionBarWithNavController()に追加
```kotlin:MainActivity.kt
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
```
##### 4. onSupportNavigateUp()を追加
`onCreate()`メソッドの下に追加する。

```kotlin:MainActivity.kt
override fun onSupportNavigateUp(): Boolean {
   val navController = this.findNavController(R.id.navHostFragment)
   return NavigationUI.navigateUp(navController, drawerLayout)
}
```

# 実行結果
<img width="350" alt="Screenshot_1612850140.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663839/4c523150-e6f7-25de-e813-f58a642f4dc4.png">