はじめに
Android のダイアログとかポップぽいものを Popup としてまとめました。その2!!
今回は Dialog について!よく使いそうなやつだけどハマりポイントがめっちゃ多い。。。
ソースは github にあげてます↓↓↓
ソース(github)
Dialog
ダイアログ表示するやつ(たぶん iOS でいう UIAlertController だと思う)
よく下記のような実装をみるけどこれだと画面回転時にクラッシュするので毎回 DialogFragment を使わないといけないらしい。。。(わりとめんどくさい。。。)
| 
					 1 2 3 4 5 6 7 8  | 
						// だめなやつ AlertDialog.Builder(this)             .setTitle("タイトル")             .setMessage("メッセージ")             .setPositiveButton("OK") { dialog, which ->                   // OK押下時の処理             }             .show()  | 
					
実装
標準
標準のダイアログ表示(タイトル、メッセージ、ポジティブボタン、ネガティブボタン、ニュートラルボタンの表示)たぶんボタンの並び順は OS バージョンで異なる
| パターン1 | パターン2 | パターン3 | パターン4 | 
|---|---|---|---|
![]()  | 
![]()  | 
![]()  | 
![]()  | 
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76  | 
						class SimpleDialogFragment : DialogFragment() {     interface SimpleDialogListener {         fun onDialogPositiveClick(dialog: DialogFragment)         fun onDialogNegativeClick(dialog: DialogFragment)         fun onDialogNeutralClick(dialog: DialogFragment)     }     private var listener: SimpleDialogListener? = null     companion object {         private const val ARGUMENTS_TITLE = "ARGUMENTS_TITLE"         private const val ARGUMENTS_MESSAGE = "ARGUMENTS_MESSAGE"         private const val ARGUMENTS_POSITIVE_TITLE = "ARGUMENTS_POSITIVE_TITLE"         private const val ARGUMENTS_NEGATIVE_TITLE = "ARGUMENTS_NEGATIVE_TITLE"         private const val ARGUMENTS_NEUTRAL_TITLE = "ARGUMENTS_NEUTRAL_TITLE"         fun newInstance(title: String? = null, message: String? = null,                         positiveTitle: String? = null, negativeTitle: String? = null,                         neutralTitle: String? = null): SimpleDialogFragment             = SimpleDialogFragment().apply {                 isCancelable = false // 背景タップで閉じないように設定                 arguments = Bundle().apply {                     putString(ARGUMENTS_TITLE, title)                     putString(ARGUMENTS_MESSAGE, message)                     putString(ARGUMENTS_POSITIVE_TITLE, positiveTitle)                     putString(ARGUMENTS_NEGATIVE_TITLE, negativeTitle)                     putString(ARGUMENTS_NEUTRAL_TITLE, neutralTitle)                 }             }     }     override fun onAttach(context: Context) {         super.onAttach(context)         listener = context as? SimpleDialogListener     }     override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {         var title: String? = null         var message: String? = null         var positiveTitle: String? = null         var negativeTitle: String? = null         var neutralTitle: String? = null         arguments?.let {             title = it.getString(ARGUMENTS_TITLE)             message = it.getString(ARGUMENTS_MESSAGE)             positiveTitle = it.getString(ARGUMENTS_POSITIVE_TITLE)             negativeTitle = it.getString(ARGUMENTS_NEGATIVE_TITLE)             neutralTitle = it.getString(ARGUMENTS_NEUTRAL_TITLE)         }         return activity?.let { activity ->             val builder = AlertDialog.Builder(activity)             title?.let {                 builder.setTitle(it)             }             message?.let {                 builder.setMessage(it)             }             positiveTitle?.let {                 builder.setPositiveButton(it) { _, _ ->                     listener?.onDialogPositiveClick(this)                 }             }             negativeTitle?.let {                 builder.setNegativeButton(it) { _, _ ->                     listener?.onDialogNegativeClick(this)                 }             }             neutralTitle?.let {                 builder.setNeutralButton(it) { _, _ ->                     listener?.onDialogNeutralClick(this)                 }             }             return builder.create()         } ?: throw IllegalStateException("Activity cannot be null")     } }  | 
					
Activity 側の実装
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42  | 
						class DialogActivity : AppCompatActivity(), SimpleDialogFragment.SimpleDialogListener {     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContentView(R.layout.activity_dialog)         findViewById<Button>(R.id.button1).setOnClickListener {             val dialog = SimpleDialogFragment.newInstance("タイトル", "メッセージ", "OK",                 "Cancel", "Neutral")             dialog.show(supportFragmentManager, "A")         }         findViewById<Button>(R.id.button2).setOnClickListener {             val dialog = SimpleDialogFragment.newInstance("タイトル", "メッセージ", "OK",                 "Cancel")             dialog.show(supportFragmentManager, "B")         }         findViewById<Button>(R.id.button3).setOnClickListener {             val dialog = SimpleDialogFragment.newInstance("タイトル", "メッセージ", "OK")             dialog.show(supportFragmentManager, "C")         }         findViewById<Button>(R.id.button4).setOnClickListener {             val dialog = SimpleDialogFragment.newInstance(message = "メッセージ", positiveTitle = "OK",                 negativeTitle = "Cancel", neutralTitle = "Neutral")             dialog.show(supportFragmentManager, "D")         }     }     override fun onDialogPositiveClick(dialog: DialogFragment) {         Log.d("TAG", dialog.tag)     }     override fun onDialogNegativeClick(dialog: DialogFragment) {         Log.d("TAG", dialog.tag)     }     override fun onDialogNeutralClick(dialog: DialogFragment) {         Log.d("TAG", dialog.tag)     } }  | 
					
汎用的にしようと思うとこんな感じになってしまう。。。ボタン押下時のイベントを取りたい場合はリスナーを使用するがセッターを用意して下記のようにすると画面回転時に Activity が再生成されるので登録したリスナーがnullになってしまう。。。解決策としてはリスナーを onAttach で設定するしかないように思う。(使い勝手悪い。。。)
| 
					 1 2 3 4 5 6 7 8 9 10 11 12  | 
						// だめなやつ val dialog = SimpleDialogFragment.newInstance("タイトル", "メッセージ", "OK",     "Cancel", "Neutral") dialog.setListener (object: SimpleDialogFragment.SimpleDialogListener {     override fun onDialogPositiveClick(dialog: DialogFragment) {     }     override fun onDialogNegativeClick(dialog: DialogFragment) {     }     override fun onDialogNeutralClick(dialog: DialogFragment) {     } }) dialog.show(supportFragmentManager, "A")  | 
					
リスト

| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46  | 
						class SimpleListDialogFragment : DialogFragment() {     interface SimpleListDialogFragmentListener {         fun onListDialogClick(dialog: DialogFragment, which: Int)     }     private var listener: SimpleListDialogFragmentListener? = null     companion object {         private const val ARGUMENTS_TITLE = "ARGUMENTS_TITLE"         private const val ARGUMENTS_ITEMS = "ARGUMENTS_ITEMS"         fun newInstance(title: String? = null, items: Array<String>): SimpleListDialogFragment                 = SimpleListDialogFragment().apply {             isCancelable = false             arguments = Bundle().apply {                 putString(ARGUMENTS_TITLE, title)                 putStringArray(ARGUMENTS_ITEMS, items)             }         }     }     override fun onAttach(context: Context) {         super.onAttach(context)         listener = context as? SimpleListDialogFragmentListener     }     override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {         var title: String? = null         var items: Array<String>? = null         arguments?.let {             title = it.getString(ARGUMENTS_TITLE)             items = it.getStringArray(ARGUMENTS_ITEMS)         }         return activity?.let { activity ->             val builder = AlertDialog.Builder(activity)             title?.let {                 builder.setTitle(it)             }             items?.let {                 builder.setItems(it) { _, which ->                     listener?.onListDialogClick(this, which)                 }             }             return builder.create()         } ?: throw IllegalStateException("Activity cannot be null")     } }  | 
					
Activity 側
| 
					 1 2 3 4 5 6 7 8  | 
						// 表示処理 val dialog = SimpleListDialogFragment.newInstance("タイトル", arrayOf("Red", "Green", "Blue")) dialog.show(supportFragmentManager, "TAG") // リスナー設定 override fun onListDialogClick(dialog: DialogFragment, which: Int) {     Log.d("TAG", which.toString()) }  | 
					
ラジオボタン

| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83  | 
						class SimpleRadioDialogFragment : DialogFragment() {     interface SimpleRadioDialogFragmentListener {         fun onRadioDialogPositiveClick(dialog: DialogFragment, checkedItem: Int)         fun onRadioDialogNegativeClick(dialog: DialogFragment, checkedItem: Int)         fun onRadioDialogNeutralClick(dialog: DialogFragment, checkedItem: Int)     }     private var defaultCheckedItem = 0     private var checkedItem = 0     private var listener: SimpleRadioDialogFragmentListener? = null     companion object {         private const val ARGUMENTS_TITLE = "ARGUMENTS_TITLE"         private const val ARGUMENTS_ITEMS = "ARGUMENTS_ITEMS"         private const val ARGUMENTS_POSITIVE_TITLE = "ARGUMENTS_POSITIVE_TITLE"         private const val ARGUMENTS_NEGATIVE_TITLE = "ARGUMENTS_NEGATIVE_TITLE"         private const val ARGUMENTS_NEUTRAL_TITLE = "ARGUMENTS_NEUTRAL_TITLE"         private const val ARGUMENTS_DEFAULT_CHECKED_ITEM = "ARGUMENTS_DEFAULT_CHECKED_ITEM"         fun newInstance(title: String? = null, items: Array<String>, defaultCheckedItem: Int = 0,                         positiveTitle: String? = null, negativeTitle: String? = null,                         neutralTitle: String? = null): SimpleRadioDialogFragment                 = SimpleRadioDialogFragment().apply {             isCancelable = false             arguments = Bundle().apply {                 putString(ARGUMENTS_TITLE, title)                 putStringArray(ARGUMENTS_ITEMS, items)                 putInt(ARGUMENTS_DEFAULT_CHECKED_ITEM, defaultCheckedItem)                 putString(ARGUMENTS_POSITIVE_TITLE, positiveTitle)                 putString(ARGUMENTS_NEGATIVE_TITLE, negativeTitle)                 putString(ARGUMENTS_NEUTRAL_TITLE, neutralTitle)             }         }     }     override fun onAttach(context: Context) {         super.onAttach(context)         listener = context as? SimpleRadioDialogFragmentListener     }     override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {         var title: String? = null         var items: Array<String>? = null         var positiveTitle: String? = null         var negativeTitle: String? = null         var neutralTitle: String? = null         arguments?.let {             title = it.getString(ARGUMENTS_TITLE)             items = it.getStringArray(ARGUMENTS_ITEMS)             positiveTitle = it.getString(ARGUMENTS_POSITIVE_TITLE)             negativeTitle = it.getString(ARGUMENTS_NEGATIVE_TITLE)             neutralTitle = it.getString(ARGUMENTS_NEUTRAL_TITLE)             defaultCheckedItem = it.getInt(ARGUMENTS_DEFAULT_CHECKED_ITEM)         }         checkedItem = defaultCheckedItem         return activity?.let { activity ->             val builder = AlertDialog.Builder(activity)             title?.let {                 builder.setTitle(it)             }             items?.let {                 builder.setSingleChoiceItems(items, defaultCheckedItem) { dialog, which ->                     checkedItem = which                 }             }             positiveTitle?.let {                 builder.setPositiveButton(it) { _, _ ->                     listener?.onRadioDialogPositiveClick(this, checkedItem)                 }             }             negativeTitle?.let {                 builder.setNegativeButton(it) { _, _ ->                     listener?.onRadioDialogNegativeClick(this, checkedItem)                 }             }             neutralTitle?.let {                 builder.setNeutralButton(it) { _, _ ->                     listener?.onRadioDialogNeutralClick(this, checkedItem)                 }             }             return builder.create()         } ?: throw IllegalStateException("Activity cannot be null")     } }  | 
					
Activity 側
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  | 
						// 表示処理 val dialog = SimpleRadioDialogFragment.newInstance("タイトル", arrayOf("Red", "Green", "Blue"),     1, "OK", "Cancel", "Neutral") dialog.show(supportFragmentManager, "TAG") // リスナー設定 override fun onRadioDialogPositiveClick(dialog: DialogFragment, checkedItem: Int) {     Log.d("TAG", checkedItem.toString()) } override fun onRadioDialogNegativeClick(dialog: DialogFragment, checkedItem: Int) {     Log.d("TAG", checkedItem.toString()) } override fun onRadioDialogNeutralClick(dialog: DialogFragment, checkedItem: Int) {     Log.d("TAG", checkedItem.toString()) }  | 
					
チェックボックス

| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94  | 
						class SimpleCheckboxDialogFragment : DialogFragment() {     interface SimpleCheckboxDialogFragmentListener {         fun onRadioDialogPositiveClick(dialog: DialogFragment, checkedItems: IntArray)         fun onRadioDialogNegativeClick(dialog: DialogFragment, checkedItems: IntArray)         fun onRadioDialogNeutralClick(dialog: DialogFragment, checkedItems: IntArray)     }     private var defaultCheckedItems = ArrayList<Int>()     private var checkedItems = ArrayList<Int>()     private var listener: SimpleCheckboxDialogFragmentListener? = null     companion object {         private const val ARGUMENTS_TITLE = "ARGUMENTS_TITLE"         private const val ARGUMENTS_ITEMS = "ARGUMENTS_ITEMS"         private const val ARGUMENTS_POSITIVE_TITLE = "ARGUMENTS_POSITIVE_TITLE"         private const val ARGUMENTS_NEGATIVE_TITLE = "ARGUMENTS_NEGATIVE_TITLE"         private const val ARGUMENTS_NEUTRAL_TITLE = "ARGUMENTS_NEUTRAL_TITLE"         private const val ARGUMENTS_DEFAULT_CHECKED_ITEMS = "ARGUMENTS_DEFAULT_CHECKED_ITEMS"         fun newInstance(title: String? = null, items: Array<String>, defaultCheckedItems: ArrayList<Int> = arrayListOf(),                         positiveTitle: String? = null, negativeTitle: String? = null,                         neutralTitle: String? = null): SimpleCheckboxDialogFragment                 = SimpleCheckboxDialogFragment().apply {             isCancelable = false             arguments = Bundle().apply {                 putString(ARGUMENTS_TITLE, title)                 putStringArray(ARGUMENTS_ITEMS, items)                 putIntegerArrayList(ARGUMENTS_DEFAULT_CHECKED_ITEMS, defaultCheckedItems)                 putString(ARGUMENTS_POSITIVE_TITLE, positiveTitle)                 putString(ARGUMENTS_NEGATIVE_TITLE, negativeTitle)                 putString(ARGUMENTS_NEUTRAL_TITLE, neutralTitle)             }         }     }     override fun onAttach(context: Context) {         super.onAttach(context)         listener = context as? SimpleCheckboxDialogFragmentListener     }     override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {         var title: String? = null         var items: Array<String>? = null         var positiveTitle: String? = null         var negativeTitle: String? = null         var neutralTitle: String? = null         arguments?.let {             title = it.getString(ARGUMENTS_TITLE)             items = it.getStringArray(ARGUMENTS_ITEMS)             positiveTitle = it.getString(ARGUMENTS_POSITIVE_TITLE)             negativeTitle = it.getString(ARGUMENTS_NEGATIVE_TITLE)             neutralTitle = it.getString(ARGUMENTS_NEUTRAL_TITLE)             it.getIntegerArrayList(ARGUMENTS_DEFAULT_CHECKED_ITEMS)?.let {items ->                 defaultCheckedItems = items             }         }         checkedItems = defaultCheckedItems         return activity?.let { activity ->             val builder = AlertDialog.Builder(activity)             title?.let {                 builder.setTitle(it)             }             items?.let {                 var checkedBoolItems = ArrayList<Boolean>()                 it.forEachIndexed { index, _ ->                     checkedBoolItems.add(checkedItems.contains(index))                 }                 builder.setMultiChoiceItems(items, checkedBoolItems.toBooleanArray()) { dialog, which, isChecked ->                     if (isChecked) {                         checkedItems.add(which)                     } else {                         checkedItems.remove(which)                     }                 }             }             positiveTitle?.let {                 builder.setPositiveButton(it) { _, _ ->                     listener?.onRadioDialogPositiveClick(this, checkedItems.toIntArray())                 }             }             negativeTitle?.let {                 builder.setNegativeButton(it) { _, _ ->                     listener?.onRadioDialogNegativeClick(this, checkedItems.toIntArray())                 }             }             neutralTitle?.let {                 builder.setNeutralButton(it) { _, _ ->                     listener?.onRadioDialogNeutralClick(this, checkedItems.toIntArray())                 }             }             return builder.create()         } ?: throw IllegalStateException("Activity cannot be null")     } }  | 
					
Activity 側
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  | 
						// 表示処理 val dialog = SimpleCheckboxDialogFragment.newInstance("タイトル", arrayOf("Red", "Green", "Blue"),     arrayListOf(1, 2), "OK", "Cancel", "Neutral") dialog.show(supportFragmentManager, "TAG") // リスナー設定 override fun onRadioDialogPositiveClick(dialog: DialogFragment, checkedItems: IntArray) {     Log.d("TAG", checkedItems.contentToString()) } override fun onRadioDialogNegativeClick(dialog: DialogFragment, checkedItems: IntArray) {     Log.d("TAG", checkedItems.contentToString()) } override fun onRadioDialogNeutralClick(dialog: DialogFragment, checkedItems: IntArray) {     Log.d("TAG", checkedItems.contentToString()) }  | 
					
カスタム
xml で View を指定してカスタムもできる。ボタンとかもカスタムできるけどそこをカスタムするのはどうなんだろう??(positiveButton とか使わずに Button を置いてそっちのイベントを取ればいける)

| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72  | 
						class CustomDialogFragment : DialogFragment() {     interface CustomDialogFragmentListener {         fun onDialogPositiveClick(dialog: DialogFragment)         fun onDialogNegativeClick(dialog: DialogFragment)         fun onDialogNeutralClick(dialog: DialogFragment)     }     private var listener: CustomDialogFragmentListener? = null     companion object {         private const val ARGUMENTS_TITLE = "ARGUMENTS_TITLE"         private const val ARGUMENTS_POSITIVE_TITLE = "ARGUMENTS_POSITIVE_TITLE"         private const val ARGUMENTS_NEGATIVE_TITLE = "ARGUMENTS_NEGATIVE_TITLE"         private const val ARGUMENTS_NEUTRAL_TITLE = "ARGUMENTS_NEUTRAL_TITLE"         fun newInstance(title: String? = null,                         positiveTitle: String? = null, negativeTitle: String? = null,                         neutralTitle: String? = null): CustomDialogFragment                 = CustomDialogFragment().apply {             isCancelable = false             arguments = Bundle().apply {                 putString(ARGUMENTS_TITLE, title)                 putString(ARGUMENTS_POSITIVE_TITLE, positiveTitle)                 putString(ARGUMENTS_NEGATIVE_TITLE, negativeTitle)                 putString(ARGUMENTS_NEUTRAL_TITLE, neutralTitle)             }         }     }     override fun onAttach(context: Context) {         super.onAttach(context)         listener = context as? CustomDialogFragmentListener     }     override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {         var title: String? = null         var positiveTitle: String? = null         var negativeTitle: String? = null         var neutralTitle: String? = null         arguments?.let {             title = it.getString(ARGUMENTS_TITLE)             positiveTitle = it.getString(ARGUMENTS_POSITIVE_TITLE)             negativeTitle = it.getString(ARGUMENTS_NEGATIVE_TITLE)             neutralTitle = it.getString(ARGUMENTS_NEUTRAL_TITLE)         }         return activity?.let { activity ->             val builder = AlertDialog.Builder(activity)             val inflater = requireActivity().layoutInflater             val view = inflater.inflate(R.layout.custom_dialog, null)             builder.setView(view)             title?.let {                 view.findViewById<TextView>(R.id.title).text = it             }             positiveTitle?.let {                 builder.setPositiveButton(it) { _, _ ->                     listener?.onDialogPositiveClick(this)                 }             }             negativeTitle?.let {                 builder.setNegativeButton(it) { _, _ ->                     listener?.onDialogNegativeClick(this)                 }             }             neutralTitle?.let {                 builder.setNeutralButton(it) { _, _ ->                     listener?.onDialogNeutralClick(this)                 }             }             return builder.create()         } ?: throw IllegalStateException("Activity cannot be null")     } }  | 
					
custom_dialog.xml
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48  | 
						<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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:orientation="vertical"     android:layout_width="wrap_content"     android:layout_height="wrap_content">     <LinearLayout         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:gravity="center_vertical"         android:padding="16dp"         android:background="@color/colorAccent">         <ImageView             android:layout_width="24dp"             android:layout_height="24dp"             app:srcCompat="@android:mipmap/sym_def_app_icon" />         <TextView android:id="@+id/title"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:layout_marginStart="8dp"             android:textColor="#FFF"             tools:text="タイトル"             />     </LinearLayout>     <EditText         android:id="@+id/username"         android:inputType="textEmailAddress"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:layout_marginTop="16dp"         android:layout_marginStart="4dp"         android:layout_marginEnd="4dp"         android:layout_marginBottom="4dp"         android:hint="Name" />     <EditText         android:id="@+id/password"         android:inputType="textPassword"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:layout_marginTop="4dp"         android:layout_marginStart="4dp"         android:layout_marginEnd="4dp"         android:layout_marginBottom="16dp"         android:fontFamily="sans-serif"         android:hint="Password"/> </LinearLayout>  | 
					
Activity 側
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  | 
						// 表示処理 val dialog = CustomDialogFragment.newInstance("タイトル",                 "OK", "Cancel", "Neutral") dialog.show(supportFragmentManager, "TAG") // リスナー設定 override fun onDialogPositiveClick(dialog: DialogFragment) {     Log.d("TAG", dialog.tag) } override fun onDialogNegativeClick(dialog: DialogFragment) {     Log.d("TAG", dialog.tag) } override fun onDialogNeutralClick(dialog: DialogFragment) {     Log.d("TAG", dialog.tag) }  | 
					
Activityをダイアログ表示する
マニフェストファイルの指定の Activity を下記のように設定すると Activity をダイアログ表示できる。
| 
					 1  | 
						<activity android:theme="@android:style/Theme.Holo.Dialog" >  | 
					
AppCompatActivity を継承しているとクラッシュしたけど Activity を継承させると下記のように表示された。(ToastActivityを一時的に書き換えて表示したやつ)

ProgressDialog (2020/07/30追記)
ProgressDialog というのもあるがわりと前に非推奨になった。代替クラスは特になくそもそも下記のようにユーザーの操作を妨げる UI はやめろということらしい
注意:Android には、進行状況バーを含むダイアログを表示する ProgressDialog という別のダイアログ クラスがあります。このウィジェットは、ユーザーが進捗の表示中はアプリを操作できないため、非推奨となっています。読み込み中または不確定な進捗状況を表示する必要がある場合は、Progress & Activity のデザイン ガイドラインに従って、ProgressDialog を使用する代わりに、レイアウトで ProgressBar を使用してください。
とはいっても通信中とかに表示したい場合は DialogFragment で自作するしかない。。。
こんな感じ
| ProgressDialog | 自作ダイアログ | 
|---|---|
![]()  | 
![]()  | 
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38  | 
						class CustomProgressDialogFragment : DialogFragment() {     companion object {         private const val ARGUMENTS_TITLE = "ARGUMENTS_TITLE"         private const val ARGUMENTS_MESSAGE = "ARGUMENTS_MESSAGE"         fun newInstance(title: String? = null, message: String? = null): CustomProgressDialogFragment                 = CustomProgressDialogFragment().apply {             isCancelable = false             arguments = Bundle().apply {                 putString(ARGUMENTS_TITLE, title)                 putString(ARGUMENTS_MESSAGE, message)             }         }     }     override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {         var title: String? = null         var message: String? = null         arguments?.let {             title = it.getString(ARGUMENTS_TITLE)             message = it.getString(ARGUMENTS_MESSAGE)         }         return activity?.let { activity ->             val builder = AlertDialog.Builder(activity)             val inflater = requireActivity().layoutInflater             val view = inflater.inflate(R.layout.custom_progress_dialog, null)             builder.setView(view)             title?.let {                 builder.setTitle(it)             }             message?.let {                 view.findViewById<TextView>(R.id.message).text = it             }             return builder.create()         } ?: throw IllegalStateException("Activity cannot be null")     } }  | 
					
custom_progress_dialog.xml
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22  | 
						<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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:orientation="vertical"     android:layout_width="wrap_content"     android:layout_height="wrap_content">     <LinearLayout         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:gravity="center_vertical"         android:padding="16dp">         <ProgressBar             android:layout_width="wrap_content"             android:layout_height="wrap_content"/>         <TextView android:id="@+id/message"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:layout_marginStart="8dp"             tools:text="メッセージ" />     </LinearLayout> </LinearLayout>  | 
					
Activity 側
| 
					 1 2 3 4 5 6  | 
						val dialog = CustomProgressDialogFragment.newInstance("タイトル", "メッセージ") dialog.show(supportFragmentManager, "D") Handler(Looper.getMainLooper()).postDelayed(Runnable {     // 3秒後に非表示     dialog.dismiss() }, 3000)  | 
					
参照
さいごに
iOS に比べるとカスタム性が非常に高いけどちょっと高すぎて悩んでしまう感じがする。(なんでもできちゃいそうなのでお客さんに仕様上無理です!とか言いづらそう。。。)
Android は iOS と同じ感覚でやっちゃうとハマるので気をつけた方がよさそう。特に画面回転とか。。。
  
  
  
  






コメント