30歳からの開発日記

30歳でエンジニア転職した元営業の備忘録。

【Android】カスタマイズできる DialogFragment 継承クラスを作る【コピペでOK】

今回やること

DialogFragment を使ったダイアログを実装します。

ダイアログを表示するには DialogFragment を継承したクラスを自作する必要がありますが、毎回実装するのが手間なので、コピペで使えるシンプルなクラスを実装してみます。

DialogFragment の罠

この DialogFragment 継承クラスを作るとき、データを引数として渡すことは避けるべきです。ダイアログが表示された状態で画面を回転させるとダイアログも再生成されますが、このとき自動的に引数なしのコンストラクタを呼ぼうとするため、それがないとアプリがクラッシュします。

class SimpleDialogFragment(val title: String, val message: String, ...) : DialogFragment() {
    // ダメなパターン。DialogFragment の継承クラスは引数なしを実装するべき。
}

DialogFragment 継承クラスを実装するときは必ず引数なしコンストラクを用意しましょう。

(画面の回転でアクティビティやフラグメントを再生成しない設定をしている場合は関係ありません。)

実装

上記の罠を回避するために、必要なデータはセッターを使ってクラスに渡すようにします。

class SimpleDialogFragment : DialogFragment() {

    private var title: String = ""
    private var message: String = ""
    private var positiveButtonLabel: String = ""
    private var negativeButtonLabel: String = ""
    private var positiveButtonClickListener: DialogInterface.OnClickListener? = null
    private var negativeButtonClickListener: DialogInterface.OnClickListener? = null

    fun setTitle(title: String) {
        this.title = title
    }

    fun setMessage(message: String) {
        this.message = message
    }

    fun setPositiveButton(label: String, listener: DialogInterface.OnClickListener?) {
        positiveButtonLabel = label
        positiveButtonClickListener = listener
    }

    fun setNegativeButton(label: String, listener: DialogInterface.OnClickListener?) {
        negativeButtonLabel = label
        negativeButtonClickListener = listener
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        activity ?: throw IllegalStateException("Activity cannot be null.")
        val builder = AlertDialog.Builder(activity)
        return builder.setTitle(title)
            .setMessage(message)
            .setPositiveButton(positiveButtonLabel, positiveButtonClickListener)
            .setNegativeButton(negativeButtonLabel, negativeButtonClickListener)
            .create()
    }
}

使い方

スコープ関数を使うことで、タイトル、メッセージ、ボタンの設定がスマートに記述することができます。

val dialog = SimpleDialogFragment().apply {
    setTitle("タイトル")
    setMessage("メッセージ")
    setPositiveButton("はい", DialogInterface.OnClickListener {dialog, which ->
        Toast.makeText(this, "はいが押されました。", Toast.LENGTH_LONG).show()
    })
    setNegativeButton("いいえ", null)
}
dialog.show(supportFragmentManager, "sample_dialg")