Android Show Busy/Loading and Prevent Touch (using DialogFragment) - Kotlin

April 13, 2019
Dialog with transparent background and disable black opacity

Solution 1

You can disable activity and show/hide a ProgressBar.

Solution 2: Dialog

The inconvinience with Solution 1 is that you always need to embeded ProgressBar into the current layout.

This solution will use a DialogFragment to display the ProgressBar.

  • Dialog comes with white inner background and black outer overlay with opacity, and prevent user from touching the activity.
  • Make the white background transparent
  • Remove outer black overlay of fragment
  • Prevent dialog dismiss by user touch
class BusyDialogFragment: DialogFragment() {
    companion object {
        private const val FRAGMENT_TAG = "busy"

        fun newInstance() = BusyDialogFragment()

        fun show(supportFragmentManager: FragmentManager): BusyDialogFragment {
            val dialog = BusyDialogFragment.newInstance()
            // prevent dismiss by user click
            dialog.isCancelable = false
            dialog.show(supportFragmentManager, FRAGMENT_TAG)
            return dialog
        }
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        // return super.onCreateView(inflater, container, savedInstanceState)

        // make white background transparent
        dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))

        return activity!!.layoutInflater.inflate(R.layout.busy, container)
    }

    override fun onStart() {
        super.onStart()

        // remove black outer overlay, or change opacity
        dialog?.window?.also { window ->
            window.attributes?.also { attributes ->
                attributes.dimAmount = 0.1f
                window.attributes = attributes
            }
        }
    }
}

Layout

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

    <ProgressBar
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

Usage: Show dialog

val busyDialog = BusyDialogFragment.show(supportFragmentManager)

Hide dialog

busyDialog.dismiss()

Use function reference to automatically show and dismiss dialog

class BusyDialog: DialogFragment() {
    companion object {
        ...

        fun <R> show(fragmentManager: FragmentManager, block: () -> R): R {
            val dialog = show(fragmentManager)
            return block().apply {
                dialog.dismiss()
            }
        }
    }

Usage

val result = BusyDialog.show(fragmentManager!!) {
    // do something
}
This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.