📱

Android:DialogFragmentからDialogFragmentを呼び出す方法

2022/10/06に公開

はじめに

DialogFragmentをつかってDialogを呼び出し、その呼び出したDialogから別のDialogを呼び出す方法について書きます。下記のGIFのように1つ目のDialogを呼び出した後、1つ目のDialogの「OK」ボタンを押すと、2つ目のDialogが表示されます。

やり方

ソースコード

上記の動画の動作例は下記のようなコードで実現します。

MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setTitle("Dialog Test")

        val displayDialog = findViewById<Button>(R.id.button)

        displayDialog.setOnClickListener{
            val dialog = firstDialog()
            val manager: FragmentManager = supportFragmentManager
            dialog.show(manager, "simple")
        }
    }
}

Dialog.kt
// 1つ目のDialog
class firstDialog : DialogFragment() {
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            // Use the Builder class for convenient dialog construction
            val builder = AlertDialog.Builder(it)
            builder.setTitle("テスト")
                .setMessage("1つ目のダイアログ")
                .setPositiveButton("OK") { firstDialogInterface, i ->
                    firstDialogInterface.dismiss()
                    val nextDialog = secondDialog()
		    // FragmentManagerの指定
                    val manager = fragmentManager
                    if (manager != null) {
                        nextDialog.show(manager, "simple")
                    }
                }
                .create()
        } ?: throw IllegalStateException("Activity cannot be null")
    }
}

// 2つ目のDialog
class secondDialog : DialogFragment() {
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            // Use the Builder class for convenient dialog construction
            val builder = AlertDialog.Builder(it)
            builder.setTitle("テスト")
                .setMessage("2つ目のダイアログ")
                .setPositiveButton("OK") { secondDialogInterface, i ->
                    secondDialogInterface.dismiss()
                }
                .create()
        } ?: throw IllegalStateException("Activity cannot be null")
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Dialog"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

失敗するやり方

先程のDialog.ktを下記のようにします。

Dialog.kt
class firstDialog : DialogFragment() {
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            // Use the Builder class for convenient dialog construction
            val builder = AlertDialog.Builder(it)
            builder.setTitle("テスト")
                .setMessage("1つ目のダイアログ")
                .setPositiveButton("OK") { secondDialogInterface, i ->
                    secondDialogInterface.dismiss()
                    val nextDialog = secondDialog()
                    //val manager = fragmentManager
		    // 変更点
                    val manager: FragmentManager = childFragmentManager
                    nextDialog.show(manager, "simple")
                }
                .create()
        } ?: throw IllegalStateException("Activity cannot be null")
    }
}

class secondDialog : DialogFragment() {
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            // Use the Builder class for convenient dialog construction
            val builder = AlertDialog.Builder(it)
            builder.setTitle("テスト")
                .setMessage("2つ目のダイアログ")
                .setPositiveButton("OK") { secondDialogInterface, i ->
                    secondDialogInterface.dismiss()
                }
                .create()
        } ?: throw IllegalStateException("Activity cannot be null")
    }
}

変更点は1つ目のDialogから2つ目のDialogを呼び出す際に、FragmentManagerをchildFragmentManagerを指定しています。

Dialog.kt
val manager: FragmentManager = childFragmentManager

これを動作させると、1つ目のDialog表示後、「OK」ボタンをおすと2つ目のDialogが表示されません。

おわりに

FragmentManagerの仕様を確認すると、childFragmentManagerはFragmentManagerの子要素であることが確認できます。そのため1つ目のDialogの消去にともなって、2つ目のDialogも消去されていると考えられます。そのため、1つ目のDialogと2つ目のDialogの表示では、それぞれのfragmentManagerに分けて指定する必要があります。
これでDialogFragmentで表示したDialogから別のDialogFragmentを呼び出すことができました。

Discussion