何かと便利なAlertDialog
ですが、引数を渡してその内容を表示させることも簡単にできます。
ViewBindingを使い柔軟にカスタマイズすることもできますが、今回はシンプルにテキストのみを呼び出し元から渡すサンプルを実装してみたいと思います。
AlertDialogについて
基本的にAndroidのDialogはタイトル
、コンテンツエリア
、PositiveButton
、NegativeButton
、NeutralButton
といった部品で構成されています(ボタンの総称をActionButton
とも言います)。
DialogとしてはAlertDialog
が最もよく使われ、Alertとはありますが別に警告に限らず様々な用途で使うことができます。
今回はMainAcitivty
でMaterialAlertDialogBuilder()
を使用する方法と、DialogFragment
を使う方法の2種類を紹介します。
作成するサンプル
ListView
に英単語の一覧を表示し、アイテムをクリックするとAlertDialog
が起動し、その単語の品詞、意味を表示するサンプルを作成します。
なおListView
のカスタマイズについては本記事では触れません。
なお今回紹介する2つの方法どちらも同じ動きをします。
コード
それでは両者のコードを見てみましょう。
MaterialAlertDialogBuilder()で実装
たぶん一番楽なやり方です。
MainActivity.kt
class MainActivity : AppCompatActivity() {
// (省略)
private inner class ListItemClickListener : AdapterView.OnItemClickListener{
// リストのアイテムがクリックされたときのイベントハンドラ
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val item = parent?.getItemAtPosition(position) as MutableMap<String, Any>
val wordName = item["name"] as String
val wordSpeech = item["speech"] as String
val wordMeaning = item["meaning"] as String
val builder = MaterialAlertDialogBuilder(this@MainActivity)
builder.setTitle(wordName)
builder.setMessage("$wordSpeech:$wordMeaning")
val dialog = builder.create()
dialog.show()
}
}
}
シンプルですね。
MaterialAlertDialogBuilder
にcontext
を渡しbuilder
オブジェクトを生成します。
生成したオブジェクトにsetTitle()
、setMessage()
で値を設定するだけですね。
ただまぁ「引数を渡す」ってのとはちょっとイメージが違うか。
今回は触れていませんがもちろん各ボタンがクリックされた場合の処理もMainAcitivty
内部に記述できます。
DialogFragmentで実装
ちゃんと(?)DialogFragment
を生成し、そこに引数を渡します。
拡張性はこちらの方が高いですね。
WordDialogFragment.kt
class WordDialogFragment : DialogFragment() {
// 表示する「単語」、「品詞」、「意味」のプロパティ
private var _word: String = ""
private var _speech: String = ""
private var _meaning: String = ""
companion object{
// インスタンス生成のメソッド
// 引数として読みだし元から「単語」、「品詞」、「意味」を受け取る
fun create(word: String, speech: String, meaning:String): WordDialogFragment{
val bundle = Bundle()
bundle.putString("Word", word)
bundle.putString("Speech", speech)
bundle.putString("Meaning", meaning)
val dialog = WordDialogFragment().also { it.arguments = bundle }
return dialog
}
}
// 引数の内容をプロパティに設定
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_word = arguments?.getString("Word") as String
_speech = arguments?.getString("Speech") as String
_meaning = arguments?.getString("Meaning") as String
}
// ダイアログの表示
// プロパティから画面部品に値を設定
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = activity?.let{
val builder = AlertDialog.Builder(it)
builder.setTitle(_word)
builder.setMessage("$_speech:$_meaning")
builder.create()
}
return dialog ?: throw IllegalStateException("Error")
}
}
すこし注意していただきたいのがメンバ変数にあたる_word
、_speech
、_meaning
のデータの持ち方(与え方?)です。
コンストラクタの引数としてこれらのデータを受け取り、onCreateDialog
でsetTitle()
しようとすると画面回転させたときにアプリが落ちます。
というのもDialogFragment
(実際にはそれ以外にもFragment
を継承しているクラスも)は、画面を回転させたりするとActivityが破棄され、そしてその都度再度生成される動きとなっているからです。
そしてその際の初期化は引数なしのコンストラクタで行われます。
なので落ちちゃうんですね。
というわけで今回のサンプルではonCreate
で引数をメンバ変数に設定し、onCreateDialog
でタイトル、メッセージにsetするという書き方をしています。
MainActivity.kt
Dialogの生成は以下の通りです。
class MainActivity : AppCompatActivity() {
// (省略)
private inner class ListItemClickListener : AdapterView.OnItemClickListener{
// リストのアイテムがクリックされたときのイベントハンドラ
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val item = parent?.getItemAtPosition(position) as MutableMap<String, Any>
val wordName = item["name"] as String
val wordSpeech = item["speech"] as String
val wordMeaning = item["meaning"] as String
// ダイアログの生成
var dialogFragment = WordDialogFragment.create(wordName, wordSpeech, wordMeaning)
dialogFragment.show(supportFragmentManager, "WordDialog")
}
}
}
こちらはDialogFragment
を呼び出しているだけですね。
create()
メソッドで引数を渡すのだけ忘れないでください。
まとめ
シンプルに引数を渡して表示するだけの内容ですが、DialogFragment
側でのデータの持ち方に少し工夫が必要ですね。
次はDialogから引数を受け取る方法についてまとめてみたいと思います。