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に置きました。