フラグメントからダイアログを呼び出す場合は、アクティビティから呼び出す方法とは少し異なります。
package com.example.sampledialoginfragment
import android.app.AlertDialog
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import androidx.fragment.app.DialogFragment
import com.example.sampledialoginfragment.databinding.FragmentBlankBinding
private const val ARG_TITLE = "title"
private const val ARG_MESSAGE = "message"
private const val ARG_INPUT_TEXT = "input text"
class InputDialog: DialogFragment() {
interface InputDialogListener {
fun onInputDialogPositiveClicked(dialog: InputDialog)
fun onInputDialogNegativeClicked(dialog: InputDialog)
}
private lateinit var listener: InputDialogListener
private var _binding: FragmentBlankBinding? = null // *0
private val binding get() = _binding!! // *0
private var title: String = ""
private var message: String = ""
private lateinit var editText: EditText
var inputText = ""
override fun onAttach(context: Context) {
super.onAttach(context)
when {
// *1
parentFragment is InputDialogListener -> listener = parentFragment as InputDialogListener
// *2
context is InputDialogListener -> listener = context
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let { // *3
title = it.getString(ARG_TITLE) ?:""
message = it.getString(ARG_MESSAGE) ?:""
inputText = it.getString(ARG_INPUT_TEXT) ?:""
}
savedInstanceState?.let {
inputText = it.getString(ARG_INPUT_TEXT, "") ?:"" // *4
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentBlankBinding.inflate(inflater, container, false) // *0
return binding.root
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
editText = EditText(context)
editText.setText(inputText)
val builder = AlertDialog.Builder(context)
.setTitle(title)
.setMessage(message)
.setView(editText)
.setPositiveButton("OK") {_, _ ->
inputText = editText.text.toString()
listener.onInputDialogPositiveClicked(this) // *5
}
.setNegativeButton("cancel") {_, _ ->
listener.onInputDialogNegativeClicked(this) // *5
}
return builder.create()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString(ARG_INPUT_TEXT, editText.text.toString()) // *6
}
companion object { // *7
@JvmStatic
fun newInstance(title: String, message: String, inputText: String) =
InputDialog().apply {
arguments = Bundle().apply {
putString(ARG_TITLE, title)
putString(ARG_MESSAGE, message)
putString(ARG_INPUT_TEXT, inputText)
}
}
}
}
*0 フラグメントでのbindingの使い方は以前のページをご覧ください。
*1 フラグメントから呼び出された場合のlistenerの設定です。
*2 アクティビティから呼び出された場合のlistenerの設定です。
両方から呼び出される場合、フラグメントから呼び出された場合もcontextはアクティビティを参照しているため、先にparentFragmentを判定しています。
*3 newInstance()でインスタンス化されたときにargumentsにパラメータを保存し、ここで読み込んでいます。
*4 画面回転した場合、回転後にテキストボックス内にテキストを復元しています。
*5 ダイアログのOKボタン、キャンセルボタン押したときの処理をlistenerに任せています。
*6 画面回転する直前にテキストボックスの中身を保管しています。
*7 インプットダイアログをインスタンス化する際にパラメータ(タイトル、メッセージ、テキストボックスの初期値)を設定できるようにしています。
package com.example.sampledialoginfragment
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.sampledialoginfragment.databinding.FragmentBlankBinding
private const val KEY_MY_TEXT = "my text"
private const val TAG_INPUT_DIALOG_1 = "my dialog 1"
class BlankFragment : Fragment(), InputDialog.InputDialogListener { // *1
private var _binding: FragmentBlankBinding? = null // *0
private val binding get() = _binding!! // *0
private var myText: String = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
myText = savedInstanceState.getString(KEY_MY_TEXT, "")
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentBlankBinding.inflate(inflater, container, false) // *0
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null // *0
}
override fun onSaveInstanceState(outState: Bundle) {
outState.putString(KEY_MY_TEXT, binding.txvSample.text.toString())
super.onSaveInstanceState(outState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.txvSample.text = myText
binding.btnTest.setOnClickListener { // *2
val str = binding.txvSample.text.toString()
val inputDialog = InputDialog.newInstance("this is title", "message from blank fragment", str)
inputDialog.show(childFragmentManager, TAG_INPUT_DIALOG_1) // *3
}
}
override fun onInputDialogPositiveClicked(dialog: InputDialog) { // *4
when (dialog.tag) {
TAG_INPUT_DIALOG_1 -> binding.txvSample.text = dialog.inputText
}
}
override fun onInputDialogNegativeClicked(dialog: InputDialog) { // *4
// do nothing.
}
}
*0 フラグメントでのbindingの使い方は以前のページをご覧ください。
*1 作成したInputDialogクラスのInputDialogListenerを継承します。
*2 インプットダイアログの新しいインスタンスを作成し、show()します。
*3 第1引数にはchildFragmentManagerを渡します。
*4 OKボタンとキャンセルボタンを押されたときの処理を記述します。dialog.tagを使って作ったダイアログを識別しています。