Skip to content

Instantly share code, notes, and snippets.

@gpeal
Created December 28, 2019 00:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gpeal/ca9ad7524305d6478861a91c4c6deb54 to your computer and use it in GitHub Desktop.
Save gpeal/ca9ad7524305d6478861a91c4c6deb54 to your computer and use it in GitHub Desktop.
/**
* Show fragment's view in a dialog, similar to [androidx.fragment.app.DialogFragment],
* but without need to extend it. Should be called from [Fragment.onViewCreated].
*
* Add this Fragment without giving it a container view then call this from onViewCreated
*/
fun Fragment.showAsDialog(
@StyleRes theme: Int = R.style.FullScreenDialog,
widthDp: Int? = null,
heightDp: Int? = null,
cancelOnTouchOutside: Boolean = true,
onCancel: (() -> Unit)? = null
): Dialog {
val fragmentName = javaClass.simpleName
Timber.i("Show $fragmentName as a dialog")
val dialog = Dialog(requireContext(), theme)
dialog.setContentView(view ?: error("fragment view must be present"))
dialog.setOnKeyListener { _, keyCode, _ -> if (keyCode == KeyEvent.KEYCODE_BACK) true else false }
var viewDestroyed = false
dialog.setOnDismissListener {
if (!viewDestroyed) {
dismiss(allowStateLoss = true)
}
}
dialog.setCanceledOnTouchOutside(cancelOnTouchOutside)
dialog.setOnCancelListener { onCancel?.invoke() }
if (widthDp != null || heightDp != null) {
if (widthDp == null) throw IllegalArgumentException("You must specify a width if you specify a height.")
if (heightDp == null) throw IllegalArgumentException("You must specify a height if you specify a width.")
dialog.window?.setLayout(widthDp.dp.toInt(), heightDp.dp.toInt())
}
// This prevents the nav bar from flashing.
// https://stackoverflow.com/a/23207365/715633
dialog.window?.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
dialog.window?.decorView?.setSystemUiVisibility(requireActivity().window.decorView.systemUiVisibility)
dialog.setOnShowListener {
if (viewDestroyed) {
Timber.i("$fragmentName was dismissed before showing")
return@setOnShowListener
}
// Clear the not focusable flag from the window.
dialog.window?.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
// Update the WindowManager with the new attributes (no nicer way I know of to do this)..
dialog.window?.windowManager?.updateViewLayout(dialog.window?.decorView, dialog.window?.getAttributes())
}
activity?.let { dialog.ownerActivity = it }
viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_START -> dialog.show()
Lifecycle.Event.ON_STOP -> dialog.hide()
Lifecycle.Event.ON_DESTROY -> {
viewDestroyed = true
dialog.dismiss()
}
else -> Unit
}
})
return dialog
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment