Jetpack Composeでダイアログを表示したい

この記事をシェア
JetpackCompose一問一答

Jetpack Composeならダイアログも簡単に表示できます。material3パッケージにはAlertDialog()というコンポーネントが用意されているので、コンポーザブル関数一つでダイアログを表示できます。これまで、DialogFragmentを継承したりして地味に面倒だったダイアログ表示は、Composeを導入することで本当に楽になりました。

やりたいこと

  • ボタンクリックイベントでダイアログを表示する。
  • ダイアログには、タイトル、テキスト、OKボタン、キャンセルボタンを表示する。
  • ボタンクリック、またはダイアログ外領域のクリックでダイアログを閉じる。
  • ダイアログの結果を取得する。

環境

  • Kotlin 1.6.10
  • Jetpack Compose 1.1.1
  • Material3 1.0.0-alpha12

ソースコード

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を配置しています。ButtononClickで、showDialog = trueをセットしています。

showDialogtrueになると、if (showDialog) { ... }の中にあるAlertDialogのコンポジションが実行され、ダイアログが表示されます。またこのあと出てきますが、showDialogfalseになると、if文の中が実行されなくなるので、ダイアログが閉じます。

ではAlertDialogを見ていきます。AlertDialogはmaterial3パッケージで定義されています。必須の引数はonDismissRequestconfirmButtonだけですが、これだけでは何も意味をなさないダイアログになってしまうので、実質的にはtitletextも必須のようなものです。

titleはダイアログの上部に表示されるタイトルです。これ自体が一つのコンポーザブル関数を指定できるスロットになっているので、複雑なレイアウトを作ることも可能ですが、多くの場合はTextを使うことになると思います。titleスロット内に配置したTextのTypographyは、HeadlineSmallが適用されます。

textはダイアログのコンテンツを指定するスロットです。これも、今回の例では単純なTextのみ表示していますが、必要に応じて複雑なUIを構築することが可能です。TextFieldなどを組み合わせて、ユーザーに何かを入力してもらうダイアログを作ることもできます。textスロット内に配置したTextのTypographyは、BodyMediumが適用されます。

confirmButtonはダイアログの内容を承諾するときにクリックするボタンを定義するためのスロットです。OKやYesなどの文字列と一緒に使われることが多いです。これも自由に拡張可能ですが、多くの場合はTextButton一つ配置すれば要求を満たせると思います。さて、このボタンのonClickコールバックに、ダイアログを閉じるための処理と、結果を取得するための処理を書いてやります。すなわち、showDialogfalseをセットし、result"OK"をセットします。こうすることで、if文の中身が実行されなくなり、AlertDialogが消えることになります。また同時に、resultの値が更新されるので、結果表示も更新されます。

dismissButtonはダイアログを閉じるボタンを定義するためのスロットです。CancelやNoなどの文字列と一緒に使われることが多いです。使い方としてはconfirmButtonと同じです。ちなみに表示位置は、confirmButtonが右下、dismissButtonがその左隣になります。これはマテリアルデザインのガイドラインに定められたとおりのレイアウトになっています。

onDismissRequestはダイアログの外側をタップした時や、端末の戻る操作をした時に呼び出されるコールバックです。上の例では、ボタンをクリックしたときと同様にダイアログを閉じる処理を書いていますが、このコールバックに何も書かなければ、ダイアログ外をタップしたり、戻る操作をしても閉じないダイアログを作ることができます。ちなみに、dismissButtonをクリックしたときにはonDismissRequestコールバックは呼び出されないので、dismissButtonをクリックして閉じたのか、ダイアログ外をタップして閉じたのかは容易に判別することができます。

まとめ

AlertDialog()は引数が多くて一見複雑に見えますが、使ってみれば非常に簡単にダイアログを実装できて便利です。これまではちょっとしたダイアログを表示するだけのためにDialogFragmentを継承して独自クラスを作成して・・・といった手間をかけていたり、それが面倒なので汎用的なダイアログクラスを自作してみたりしていたことを思うと、関数一つで様々なダイアログを作れてしまうのは隔世の感があります。ダイアログのためにJetpack Composeを導入しても損はないと思いますよ。

JetpackCompose一問一答

Jetpack Compose一問一答

コンテンツは随時追加していきます。

この記事をシェア