【Android】 MaterialAlertDialogで色々実装する

MaterialDialogに関してこういうレイアウトを作りたいと思った時に
どうしたらいいのか忘れることがあったのでレシピブック的な感じでまとめてみました．

## Dialogの導入
### 依存の追加
まずは作成したプロジェクトの`build.gradle`にMaterialDesignの依存を追加します.

```build.gradle
dependencies {
	// ...
	implementation 'com.google.android.material:material:<version>'
	// ...
}
```

`<version>`には現在のバージョンを記載します．
執筆時点(4月10日)では安定版が`1.1.0`となります．
最新版についてはGithubの[リリースページ]([Releases · material-components/material-components-android · GitHub](https://github.com/material-components/material-components-android/releases))から確認できます．

### Themeの変更
MaterialDialogを使用するには使用するActivityがMaterialDesign系のテーマを継承している必要があります．
今回はテーマに`Theme.MaterialComponents.Light`を継承させます．

## MaterialDialogの基本
### タイトル+メッセージ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82263/9e12f975-2097-0848-3cb4-39274a2fd63c.png" width=40%>

Material Alert Dialogは[Builderパターン](https://qiita.com/takutotacos/items/33cfda205ab30a43b0b1)により実装されています．以下のように`タイトル`, `メッセージ本文`を指定し、最後に`show()`を書くことで表示させることができます．

```MainActivity.kt
MaterialAlertDialogBuilder(this)
        .setTitle("タイトル")
        .setMessage("メッセージ内容\nここに表示される文字は自動で改行されるようになっています．")
        .show()
```


### ボタンを追加する
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82263/022bd970-6656-a094-922d-d3c5d1c43aed.png" width=40%>
またポジティブボタンは一行`setPositiveButton(“ボタン名", タップ時のリスナー)`を加えることで実装することができます．

```MainActivity.kt
MaterialAlertDialogBuilder(this)
        .setTitle("タイトル")
        .setMessage("メッセージ内容\nここに表示される文字は自動で改行されるようになっています．")
        .setPositiveButton("はい") { dialog, which ->

        }
        .setNegativeButton("キャンセル", null)
        .show()
```

`setPositiveButton`の第２引数には`DialogInterface`のリスナーを持つことができますし、上記のようにラムダっぽく書くこともできます．
また第２引数は`nullable`となっているため、キャンセルの場合など特に何もさせたくない場合は`null`とすることができます．

またボタンの色はアプリで指定している`colorPrimary`の色になります．


## 様々な表示パターン
### 複数のボタン
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82263/c63d7a1a-560f-89e8-8ea5-956830b3cbdd.png" width=40%>
AlertDialogに複数のボタンを配置して、それぞれで異なる動きをさせたい場合`ニュートラルボタン`というオプショナルなボタンも追加することができます．

### ラジオボタン
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82263/825e6581-fe04-b8a8-6ae3-f6a0ac188c14.png" width=40%>
AlertDialogの中に複数のラジオボタン(一つのみ選択できるボタン)を作ることができます．

`setSingleChoiceItems(選択肢の配列, 最初に選択されている番号, 選択時のリスナー)`
他のボタンと同様に**選択時のリスナー**は`null`にすることもできます．

**選択時のリスナー**のラムダ式での引数の`dialog`はダイアログ自体、`which`は選択したアイテムが何番目であるかの情報が渡ってきます．

```MainActivity.kt
MaterialAlertDialogBuilder(this)
        .setTitle("タイトル")
        .setSingleChoiceItems(arrayOf("桃", "りんご", "梨"), 0) { dialog, which ->

        }
        .setPositiveButton("はい") {dialog, which ->

        }
        .setNegativeButton("キャンセル", null)
        .show()
```

また下部のポジティブ、ネガティブボタンを使用せず、ダイアログ内の選択肢を選択してダイアログを閉じることができます．
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82263/55594240-3526-13e4-8162-996a4736e5b6.png" width=40%>
**選択時のリスナー**の引数で渡される`dialog`の`dismiss()`メソッドを呼び出すことで閉じることができます．
ダイアログを閉じる前にどの選択肢を選択したのかを取得する必要があります．

```MainActivity.kt
MaterialAlertDialogBuilder(this)
        .setTitle("タイトル")
        .setSingleChoiceItems(arrayOf("桃", "りんご", "梨"), 0) { dialog, which ->
            doSomething(which)
            dialog.dismiss()
        }
        .show()

```

ちなみにボタンの色は`AcentColor`が使用されます．

### チェックボックス
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82263/eb3a7e48-33cb-49db-037f-98c97a1ce360.png" width=40%>

チェックボックスの場合は`setMultiChoiceItems`を追加することで追加できます．
`setMultiChoiceItems`の引数には
第１引数: **項目リスト**
第２引数: **選択状態の初期状態(真偽値配列)**
第３引数: **選択時のリスナー**
の３つを必要とします．

また無名関数から受け取る引数で`isChecked`があります．
項目を選択した場合に選択状態であるかが渡されてきます．


```MainActivity.kt
MaterialAlertDialogBuilder(this)
        .setTitle("タイトル")
        .setMultiChoiceItems(arrayOf("桃", "りんご", "梨"), booleanArrayOf(false, false, false)) {dialog, which, isChecked ->

        }
        .setPositiveButton("決定") { dialog, which ->

        }
        .show()
```

### シンプルなリスト表示
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82263/9786f1f6-7350-2a55-b288-bf10363f6e03.png" width=40%>

シンプルなリスト表示は`setItems`によりリストに入れる配列と、リストをタップした際のリスナーを引数とすることで実装することができます．

```MainActivity.kt
MaterialAlertDialogBuilder(this)
                .setTitle("タイトル")
                .setItems(arrayOf("桃", "りんご", "梨", "さくらんぼ", "オレンジ")) { dialog, which ->

                }
                .show()
```

### カスタムリスト
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82263/78e8e07c-04bb-dffa-9b70-b8b7693f17d8.png" width=40%>
上のようなカスタムリストはアダプターを作成することで実装することができます．

まずカスタムアダプターを作成します．
本記事では画像のような果物の画像とテキストを使用したアダプターを作成します

```FruitItemAdapter.kt
class FruitItemAdapter(context: Context, private val layoutResourceId: Int, private val fruits: List<FruitItem>) :
    ArrayAdapter<FruitItem>(context, layoutResourceId, fruits) {

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {

        val view = convertView
            ?: (context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater).inflate(layoutResourceId, null)

        val item = fruits[position]
        val imageView = viewfindViewById<ImageView>(R.id.imageView)
        val textView = view.findViewById<TextView>(R.id.fruitText)

        imageView.setImageResource(item.image)
        textView.text = item.name

        return view
    }
}

data class FruitItem(val name: String, val image: Int)
```

続いて、果物のリストを作成し、そこからアダプターのインスタンスを生成します．
画像とテキストのカスタムレイアウトも`view_fruit_item`として作成しています．

```MainActivity.kt
val fruits = listOf(
    FruitItem("桃", R.drawable.furit_mark15_momo),
    FruitItem("りんご", R.drawable.fruit_apple),
    FruitItem("梨", R.drawable.fruit_nashi),
    FruitItem("さくらんぼ", R.drawable.furit_mark17_cherry),
    FruitItem("オレンジ", R.drawable.furit_mark18_mikan)
)

val adapter = FruitItemAdapter(this, R.layout.view_fruit_item, fruits)
```

最後にMaterialAlertDialogに作成したアダプターをセットします

```MainActivity.kt
MaterialAlertDialogBuilder(this)
    .setTitle("タイトル")
    .setAdapter(adapter) { dialog, which ->

    }
    .show()
```