LoginSignup
0
0

More than 1 year has passed since last update.

Androidで色々なDialogを出してみる

Last updated at Posted at 2022-11-25

Androidで色々なDialogって何があるの?

AndroidでDialogをだすとなると、AlertDialogが一般的ですが他にも色々あります。
参考URL
本家Android Developpers:ダイアログ

AlertDialog

一般的なこんなやつです。アクションボタンに3つの選択肢があります。

アクションボタン 意味
setPositiveButton アクションを受け入れて続行する場合に使用します(「OK」アクション)。
setNegativeButton アクションをキャンセルする場合に使用します。
setNeutralButton どちらでもない。後で、とか。
AlertDialog.Builder(this)
    .setTitle("タイトル")
    .setMessage("メッセージ")
    .setPositiveButton("OK") { dialog,  id ->
        Toast.makeText(applicationContext, "OK押しましたね", Toast.LENGTH_LONG).show()
    }
    .setNegativeButton("Cancel") {dialog, id ->
        Toast.makeText(applicationContext, "Cancel押しましたね", Toast.LENGTH_LONG).show()
    }
    .setNeutralButton("Late") {dialog, id ->
        Toast.makeText(applicationContext, "Late押しましたね", Toast.LENGTH_LONG).show()
    }
    .show()

基本的なDialog

DialogFragmentを継承します。アクションボタンは、AlertDialog同様3つの選択肢があります。

どのアクションボタンを押したのかをToastに表示するようにしてみました。

class BasicDialogFragment : DialogFragment() {
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            val builder = AlertDialog.Builder(it)
            builder.setMessage("Start Game?")
                // アクションを受け入
                .setPositiveButton("start") { dialog, id ->
                    which(dialog, id)
                }
                // アクションをキャンセル
                .setNegativeButton("cancel") { dialog, id ->
                    which(dialog, id)
                }
                // どっちでもない
                .setNeutralButton("N/A") { dialog, id ->
                    which(dialog, id)
                }
            builder.create()
        } ?: throw java.lang.IllegalArgumentException("Activity cannot be null")
    }

    fun which(daialog: DialogInterface, id: Int) {
        when (id) {
            DialogInterface.BUTTON_POSITIVE ->
                Toast.makeText(context, "start押しましたね", Toast.LENGTH_LONG).show()
            DialogInterface.BUTTON_NEGATIVE ->
                Toast.makeText(context, "cancel押しましたね", Toast.LENGTH_LONG).show()
            DialogInterface.BUTTON_NEUTRAL ->
                Toast.makeText(context, "N/A押しましたね", Toast.LENGTH_LONG).show()
            else -> {}
        }
    }
}

リスト形式のDialog

これもDialogFragmentを継承します。リストの中のどれか1個を選択したら完了です。

これもどれを選んだのかをわかるようにしてみました。

class ListDialogFragment : DialogFragment() {
    var selectId: Int = -1
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

        return activity?.let {
            val builder = AlertDialog.Builder(it)
            builder.setTitle("色を選んでください")
                .setItems(arrayOf("赤", "青", "黄")) { dialog, id ->
                    selectId = id
                    which(dialog, id)
                }
                builder.create()
        } ?: throw java.lang.IllegalArgumentException("Activity cannot be null")
    }

    fun which(daialog: DialogInterface, id: Int) {
        when (id) {
            0 -> Toast.makeText(context, "赤を押しましたね", Toast.LENGTH_LONG).show()
            1 -> Toast.makeText(context, "青を押しましたね", Toast.LENGTH_LONG).show()
            2 -> Toast.makeText(context, "黄を押しましたね", Toast.LENGTH_LONG).show()
            else -> {}
        }
    }
}

チェックボックス形式のDialog

これもDialogFragmentを継承します。チェックボックスなので複数選択可能です。アクションボタンはsetPositiveButtonと、setNegativeButtonだけです。(setNeutralButtonはない)

これも同様にどれが選択されたのかわかるようにしてみました。

class CheckBoxDialogFragment : DialogFragment() {
    val selectedItems = ArrayList<Int>()
    val toppingList = arrayOf("オニオン", "レタス", "トマト")
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            val builder = AlertDialog.Builder(it)
            builder.setTitle("トッピング選んでください")
                .setMultiChoiceItems(toppingList, null) { dialog, which, isChecked ->
                    if (isChecked) {
                        selectedItems.add(which)
                    } else if (selectedItems.contains(which)) {
                        selectedItems.remove(which)
                    }
                }
                .setPositiveButton("OK") { dialog, id ->
                    which(dialog, id)
                }
                .setNegativeButton("Cancel") { dialog, id ->
                    which(dialog, id)
                }
            builder.create()
        } ?: throw java.lang.IllegalArgumentException("Activity cannot be null")
    }

    fun which(daialog: DialogInterface, id: Int) {
        when (id) {
            DialogInterface.BUTTON_POSITIVE -> {
                val sb = StringBuilder()
                selectedItems.forEach { it ->
                    sb.append(toppingList[it] + ",")
                }
                Toast.makeText(context, "OKを押しましたね。${sb.toString()}", Toast.LENGTH_LONG).show()
            }
            DialogInterface.BUTTON_NEGATIVE ->
                Toast.makeText(context, "Cancelを押しましたね", Toast.LENGTH_LONG).show()
            else -> {}
        }
    }
}

カスタム形式のDialog

最後にカスタム形式のDialogです。これは、上の他のDialogとは違ってlayout xmlを持っています。layoutで好きなようにカスタマイズ可能です。公式のサンプルに倣ってログインの時につかうようなダイアログを作ってみました。

これもDialogFragmentを継承します。

class CustomLayoutDialogFragment : DialogFragment() {
    private lateinit var binding: DialogSigninBinding
    lateinit var userName: EditText
    lateinit var password: EditText

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

        return activity?.let {
            val builder = AlertDialog.Builder(it)
            binding = DialogSigninBinding.inflate(requireActivity().layoutInflater)
            userName = binding.username
            password = binding.password
            builder.setView(binding.root)
                .setPositiveButton("Login") { dialog, id ->
                    which(dialog, id)
                }
                .setNegativeButton("Cancel") { dialog, id ->
                    getDialog()?.cancel()
                    which(dialog, id)
                }
                builder.create()
        } ?: throw java.lang.IllegalArgumentException("Activity cannot be null")
    }

    fun which(daialog: DialogInterface, id: Int) {
        when (id) {
            DialogInterface.BUTTON_POSITIVE ->
                Toast.makeText(context, "Loginを押しましたね。${userName.text.toString()} ${password.text.toString()}", Toast.LENGTH_LONG).show()
            DialogInterface.BUTTON_NEGATIVE ->
                Toast.makeText(context, "Cancelを押しましたね", Toast.LENGTH_LONG).show()
            else -> {}
        }
    }
}

layout xmlは普通にレイアウトエディタで編集可能です。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="64dp"
        android:background="#FFFFBB33"
        android:contentDescription="login"
        android:scaleType="center"
        android:src="@android:drawable/ic_lock_idle_lock"/>

    <EditText
        android:id="@+id/username"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:layout_marginLeft="4dp"
        android:layout_marginTop="16dp"
        android:layout_marginRight="4dp"
        android:layout_marginBottom="4dp"
        android:hint="ユーザネーム"
        android:inputType="textEmailAddress" />

    <EditText
        android:id="@+id/password"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:layout_marginLeft="4dp"
        android:layout_marginTop="4dp"
        android:layout_marginRight="4dp"
        android:layout_marginBottom="16dp"
        android:fontFamily="sans-serif"
        android:hint="パスワード"
        android:inputType="textPassword" />
</LinearLayout>

MainActivityからDialogFragmentを継承しているDialogを呼ぶ

MainActivityからDialogFragmentを継承しているDialogを呼ぶ場合はshowメソッドを引数を付けて呼びます

BasicDialogFragment().show(supportFragmentManager, "Basic Dialog")
(中略)
ListDialogFragment().show(supportFragmentManager, "List Dialog")
(中略)
CheckBoxDialogFragment().show(supportFragmentManager, "CheckBox Dialog")
(中略)
CustomLayoutDialogFragment().show(supportFragmentManager,"Custom Layout")

第1引数のsupportFragmentManagerは継承しているFragmentActivity#getSupportFragmentManager()を呼んでいます。第2引数のtagは何に使われるのか、よくわかりません。javaDocによると「FragmentTransaction.addによる、このフラグメントのタグ。」と書かれているのでbackStackに使われるのかもしれません。

MainActivityに通知してみる

これだけじゃ物足りないので、DialogFragmentを継承しているものはMainActivityから呼ばれる形式なので、何が選ばれたのかMainActivityに返すようにしてみました。ます、各DialogFragmentを継承しているクラスの中でリスナを定義します。

internal lateinit var listener: NoticeDialogListener

onAttachメソッドをoverrideします

    override fun onAttach(context: Context) {
        super.onAttach(context)
        try {
            listener = context as NoticeDialogListener
        } catch (e: java.lang.ClassCastException) {
            throw java.lang.ClassCastException( (context.toString() + "must implimnet NoticeDialogListener"))
        }
    }

各、アクションボタンのメソッドの中でリスナのメソッドを呼びます。ListDialogFragmentの場合、

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

        return activity?.let {
            val builder = AlertDialog.Builder(it)
            builder.setTitle("色を選んでください")
                .setItems(arrayOf("赤", "青", "黄")) { dialog, id ->
                    selectId = id
                    listener.onDialogPositiveClick(this)
                    which(dialog, id)
                }
                builder.create()
        } ?: throw java.lang.IllegalArgumentException("Activity cannot be null")
    }

MainActivityの方は、FragmentActivityを継承し、NoticeDialogListenerを実装します。

class MainActivity : FragmentActivity(), NoticeDialogListener {
    private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater).apply {
            setContentView(this.root)
        }
        (・・・中略・・・)
    }
}

onDialogPositiveClickメソッド、onDialogNegativeClickメソッド、onDialogNeutralClickメソッドをoverrideします。
onDialogPositiveClickはどのDialogFragmentからリスナが呼ばれたか、when文で分岐するようにしました。

    override fun onDialogPositiveClick(dialog: DialogFragment) {
        Log.d("MainActivity", "onDialogPositiveClick")
        when (dialog) {
            // リスト形式の場合
            is ListDialogFragment -> {
                when (dialog.selectId) {
                    0 -> binding.textView.text = "赤を押しましたね"
                    1 -> binding.textView.text = "青を押しましたね"
                    2 -> binding.textView.text = "黄を押しましたね"
                    else -> {}
                }
            }
            // チェックボックス形式の場合
            is CheckBoxDialogFragment -> {
                val sb = StringBuilder()
                dialog.selectedItems.forEach { it ->
                    sb.append(dialog.toppingList[it] + "\r\n")
                }
                binding.textView.text = sb.toString()
            }
            // カスタムレイアウトの場合
            is CustomLayoutDialogFragment -> {
                binding.textView.text =
                    String.format("%s\n\r%s", dialog.userName.text.toString(), dialog.password.text.toString())
            }
            else -> {}
        }
    }
    override fun onDialogNegativeClick(dialog: DialogFragment) {
        Log.d("MainActivity", "onDialogNegativeClick")
    }
    override fun onDialogNeutralClick(dialog: DialogFragment) {
        Log.d("MainActivity", "onDialogNeutralClick")
    }

完成形はgitHubに置きました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0