2

I want to show a BottomSheetDialogFragment in immersive mode. Originally the nav and status bar would show when the dialog is displayed, but I can get that sorted with the code below. However, when the dialog is shown, or dismissed, the nav bar flashes for a split second. Is there a way I can show the BottomSheetDialogFragment fully immersive, without the nav bar flashing on show and dismiss?

abstract class ImmersiveBottomSheetDialogFragment<T : ViewDataBinding> : BottomSheetDialogFragment() {

    protected lateinit var binding: T

    private val systemUiVisibility: Int = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
            or View.SYSTEM_UI_FLAG_FULLSCREEN
            or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)

    fun showImmersive(
        fragmentManager: FragmentManager,
        tag: String,
        tapOutsideEnabled: Boolean = false
    ) {
        show(fragmentManager, tag)
        fragmentManager.executePendingTransactions()
        dialog?.let { dialog ->
            dialog.setCanceledOnTouchOutside(tapOutsideEnabled)
            dialog.window?.let { window ->
                window.decorView.systemUiVisibility = systemUiVisibility
                window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
            }
        }
    }
}
Francesc
  • 25,014
  • 10
  • 66
  • 84

1 Answers1

3

Add this:

override fun setupDialog(dialog: Dialog?, style: Int) {
    super.setupDialog(dialog, style)
    dialog?.window?.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
}

(from)

Also add this:

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    var viewParent = view
    while (viewParent is View) {
        viewParent.fitsSystemWindows = false
        viewParent.setOnApplyWindowInsetsListener { _, insets -> insets }
        viewParent = viewParent.parent as View?
    }
}

What does this do? DialogFragment#onActivityCreated() calls Dialog#setContentView(), which wraps the Dialog's view in a private 'wrapInBottomSheet'. In order to set the proper flags of those wrapper views, we want to set the flags after they are wrapped, e.g. after super.onActivityCreated()

Also watch this talk for info on fitsSystemWindows and window insets.

cliveleehere
  • 316
  • 1
  • 6