【Kotlin/Android】DialogFragmentの使い方!独自レイアウトのカスタムダイアログ実装

この記事からわかること
- Android Studio/KotlinのDialogFragmentの使い方
- アプリでカスタムダイアログを実装する方法
- 独自のレイアウトで作成するには?
- データや処理を渡す方法
- showとshowNowの違いと使い方
index
[open]
\ アプリをリリースしました /
環境
- Android Studio:Flamingo
- Kotlin:1.8.20
以下のようなOS標準のアラートではなく、独自のレイアウトを使用したカスタムダイアログを実装する方法をまとめていきます。

カスタムダイアログ:DialogFragment
独自のレイアウトを使用したカスタムダイアログを実装するためにはDialogFragment
を使用してFragment側にダイアログの処理を記述します。まずはDialogFragment
の利用方法を理解するためにOS標準のダイアログ処理を実装してみます。
実装の手順
- DialogFragmentを継承したFragmentクラスの作成
- onCreateDialogメソッドをオーバーライドしてダイアログ構築処理を実装
- builder.create()してDialogインスタンスを取得しreturn
ダイアログ表示処理をFragmentに切り出したことで流用しやすくなりまた、「MainActivity.kt」側などから以下のようにすっきりと呼び出すことができるようになります。

独自のレイアウトダイアログ(xml)を表示する
ダイアログとして表示するビューを独自にレイアウトしたものを実装する方法を紹介していきます。この方法は専用のレイアウトファイル(xml)を用意して表示させる流れになります。
実装の手順
- DialogFragmentを継承したFragmentクラスの作成
- 独自レイアウトのXMLファイルを準備
- onCreateDialogメソッドをオーバーライドしてダイアログ構築処理を実装
- builder.create()してDialogインスタンスを取得しreturn
1.DialogFragmentを継承したFragmentクラスの作成
まずはDialogFragmentを継承したFragmentクラスを新規で作成しておきます。関連したレイアウトファイルも一緒に新規作成しておけばOKです。
2.独自レイアウトのXMLファイルを準備
自動追加されたレイアウトファイルの中身を編集し、表示させたい独自レイアウトを実装ていきます。
3.onCreateDialogメソッドをオーバーライドしてダイアログ構築処理を実装
作成したカスタムダイアログクラスのonCreateDialog
メソッド内でレイアウトファイルを参照してビューを構築していきます。
fragment_custom_notify_dialog
レイアウトをインフレートしsetView
メソッドでAlertDialog.Builder
インスタンスに渡します。またレイアウトの中のビューにはinflate
で取得したViewから参照することが可能です。
DialogFragmentのライフサイクルはonCreateDialog
が呼ばれonViewCreated
などは呼ばれないので注意してください。
最後にActivityクラスなどからカスタムダイアログクラスをインスタンス化しshow
メソッドを呼び出すことで実装できます。

Activityなどからデータを渡して表示する
ダイアログに表示させたいデータは他のActivityなどから受け取ったデータにしたいことのが多いと思います。外部から受け取ったデータを反映させたい場合はFragmentへのデータ渡しの方法と同じでコンストラクタの引数ではクラッシュしてしまうのでBundleを介してデータを渡します。詳細な実装方法はFragment側の以下の記事を参考にしてください。
実装の流れ
- キーを準備
- データ格納用のプロパティを用意
- コンストラクタではないインスタンス生成用メソッドの準備
- onCreate内でBundleからデータを取得してプロパティにセット
ダイアログを表示させる際はnewInstance
メソッドでインスタンスを生成して使用します。
Activityなどから処理を渡して実行する
ダイアログのボタン押下時の処理を外部から渡せるようにしておけば、汎用的なカスタムダイアログクラスになり流用しやすくなります。外部から処理を渡すためにはDialogとActivityに依存関係が生じないように注意を払う必要があります。そのためDialog⇄Activity
とならないようにDialog⇄listener⇄Activity
とすることで依存し合わないようにしています。
以下の記事でFragment⇄listener⇄Activity
のやり取りを解説しているので参考にしてください。
実装の流れ
- リスナー本体を定義
- リスナーをlateinitプロパティとして定義
- リスナープロパティにセットするメソッドを用意
- 外部から渡された処理を実行したい箇所で呼び出す
Activityから処理を渡すには定義したsetOnTappedListner
メソッドを呼び出し、引数にタップ時に実行したい処理を組み込んだonTappedListner
型を渡せばOKです。
ダイアログ以外の部分のViewをタップを禁止する
ダイアログ表示している場合はデフォルトでは背景のViewをタップされた時にダイアログが閉じてしまうようになっています。これを防ぐにはsetCanceledOnTouchOutside
でタップ自体を禁止し、念の為isCancelable
もfalse
にしておくと良いです。
同じタグのダイアログを出さないようにする
タグで表示しているダイアログを識別することができるので、連続でボタンを押された時などに同じダイアログが表示されないようにダイアログを表示しているかチェックしてから表示することで重複したダイアログを表示しないようにすることができます。そのためにはsupportFragmentManager
からfindFragmentByTag
を使用して対象のDialogFragment
があるかどうかを確認します。
この場合にshow
メソッド表示させていると高速で複数回呼び出された時などに対応できず、重複して表示されてしまうことがあります。その場合はshowNow
メソッドを使用すると改善します。
showとshowNowの違いと使い方
DialogFragment
を表示するメソッドにはshow
とshowNow
メソッドがあります。定義を確認してみるとcommit
とcommitNow
の違いのようです。
showメソッド
show
メソッドは非同期的にDialogFragment
を表示。フラグメントトランザクションがコミットされたあと、次のUIスレッドの更新タイミングで表示される。
showNowメソッド
showNow
メソッドは同期的にDialogFragment
を表示。フラグメントトランザクションがコミットされ即座に表示される。
例えば以下のように流れで3つの同じフラグメントを表示する際にshowNow
だと、1番目しか表示されませんが、show
だと全て表示されてしまいます。つまり同じカスタムダイアログが表示されないようにするためにはshowNow
を使用した方が良さそうです。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。