Jetpack Composeならダイアログも簡単に表示できます。material3パッケージにはAlertDialog()
というコンポーネントが用意されているので、コンポーザブル関数一つでダイアログを表示できます。これまで、DialogFragmentを継承したりして地味に面倒だったダイアログ表示は、Composeを導入することで本当に楽になりました。
やりたいこと
- ボタンクリックイベントでダイアログを表示する。
- ダイアログには、タイトル、テキスト、OKボタン、キャンセルボタンを表示する。
- ボタンクリック、またはダイアログ外領域のクリックでダイアログを閉じる。
- ダイアログの結果を取得する。
サンプル
ソースコードはGitHubにあります。
主な環境は以下の通りです。
- Kotlin 1.7210
- Compose Compiler 1.3.2
- Compose Libraries 1.2.1
- Material3 1.0.0-rc01
- Accompanist 0.25.1
ソースコード
fun DialogSample() {
var showDialog by remember { mutableStateOf(false) }
var result by remember { mutableStateOf("Result") }
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize(),
) {
Button(
onClick = { showDialog = true },
modifier = Modifier.padding(50.dp)
) {
Text("Show Dialog")
}
Text(
text = result
)
}
if (showDialog) {
AlertDialog(
onDismissRequest = {
result = "Dismiss"
showDialog = false
},
confirmButton = {
TextButton(
onClick = {
result = "OK"
showDialog = false
}
) {
Text("OK")
}
},
dismissButton = {
TextButton(
onClick = {
result = "Cancel"
showDialog = false
}
) {
Text("Cancel")
}
},
title = {
Text("AlertDialog")
},
text = {
Text("これはJetpack Composeのダイアログです。Material3デザインに対応しています。")
},
)
}
}
初めに2つの状態変数をremember
で定義しています。showDialog
はダイアログの表示・非表示をコントロールするための変数で、result
はダイアログの結果を受け取るための変数です。どちらもコンポジションを超えて値を保持する必要があり、値が変更した時に再コンポジションが必要なので、remember
かつmutableState
で定義しています。
次のColumn
で、ダイアログを表示するためのButton
と、結果を表示するためのText
を配置しています。Button
のonClick
で、showDialog = true
をセットしています。
showDialog
がtrue
になると、if (showDialog) { ... }
の中にあるAlertDialog
のコンポジションが実行され、ダイアログが表示されます。またこのあと出てきますが、showDialog
がfalse
になると、if文の中が実行されなくなるので、ダイアログが閉じます。
ではAlertDialog
を見ていきます。AlertDialog
はmaterial3パッケージで定義されています。必須の引数はonDismissRequest
とconfirmButton
だけですが、これだけでは何も意味をなさないダイアログになってしまうので、実質的にはtitle
とtext
も必須のようなものです。
title
はダイアログの上部に表示されるタイトルです。これ自体が一つのコンポーザブル関数を指定できるスロットになっているので、複雑なレイアウトを作ることも可能ですが、多くの場合はText
を使うことになると思います。title
スロット内に配置したText
のTypographyは、HeadlineSmall
が適用されます。
text
はダイアログのコンテンツを指定するスロットです。これも、今回の例では単純なText
のみ表示していますが、必要に応じて複雑なUIを構築することが可能です。TextField
などを組み合わせて、ユーザーに何かを入力してもらうダイアログを作ることもできます。text
スロット内に配置したText
のTypographyは、BodyMedium
が適用されます。
confirmButton
はダイアログの内容を承諾するときにクリックするボタンを定義するためのスロットです。OKやYesなどの文字列と一緒に使われることが多いです。これも自由に拡張可能ですが、多くの場合はTextButton
一つ配置すれば要求を満たせると思います。さて、このボタンのonClick
コールバックに、ダイアログを閉じるための処理と、結果を取得するための処理を書いてやります。すなわち、showDialog
にfalse
をセットし、result
に"OK"
をセットします。こうすることで、if文の中身が実行されなくなり、AlertDialog
が消えることになります。また同時に、result
の値が更新されるので、結果表示も更新されます。
dismissButton
はダイアログを閉じるボタンを定義するためのスロットです。CancelやNoなどの文字列と一緒に使われることが多いです。使い方としてはconfirmButtonと同じです。ちなみに表示位置は、confirmButtonが右下、dismissButtonがその左隣になります。これはマテリアルデザインのガイドラインに定められたとおりのレイアウトになっています。
onDismissRequestはダイアログの外側をタップした時や、端末の戻る操作をした時に呼び出されるコールバックです。上の例では、ボタンをクリックしたときと同様にダイアログを閉じる処理を書いていますが、このコールバックに何も書かなければ、ダイアログ外をタップしたり、戻る操作をしても閉じないダイアログを作ることができます。ちなみに、dismissButton
をクリックしたときにはonDismissRequest
コールバックは呼び出されないので、dismissButton
をクリックして閉じたのか、ダイアログ外をタップして閉じたのかは容易に判別することができます。
まとめ
AlertDialog()
は引数が多くて一見複雑に見えますが、使ってみれば非常に簡単にダイアログを実装できて便利です。これまではちょっとしたダイアログを表示するだけのためにDialogFragment
を継承して独自クラスを作成して・・・といった手間をかけていたり、それが面倒なので汎用的なダイアログクラスを自作してみたりしていたことを思うと、関数一つで様々なダイアログを作れてしまうのは隔世の感があります。ダイアログのためにJetpack Composeを導入しても損はないと思いますよ。
コンテンツは随時追加していきます。