https://kotlinlang.org logo
Title
g

galex

05/23/2023, 9:59 AM
Hello,
BackHandler
doesn't work inside
BottomSheetDialogFragment
, how can I intercept it on the dialog and forward it myself to Compose which is the UI within
BottomSheetDialog
?
So if anyone is looking for the answer to this issue, it seems like the dialog is the one catching the
onBackPressed
event and dismisses the dialog. To have Compose be connected to it, we have to do the following: In your fragment, catches the dialog when created:
private lateinit var dialog: ComponentDialog

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return BottomSheetDialog(requireContext(), theme).apply {
        fullyExpanded()
        notDraggable()
        withoutBackgroundDim()
    }.also { dialog = it }
}
Prepare the following extensions on `ComponentDialog`:
private val ComponentDialog.asBackPressedDispatcherOwner: OnBackPressedDispatcherOwner
        get() = object : OnBackPressedDispatcherOwner {
            override val lifecycle: Lifecycle
                get() = this@asBackPressedDispatcherOwner.lifecycle
            override val onBackPressedDispatcher: OnBackPressedDispatcher
                get() = this@asBackPressedDispatcherOwner.onBackPressedDispatcher
        }
And then the only missing piece is in your ComposeView to wrap the content with `CompositionLocalProvider`:
CompositionLocalProvider(
    LocalOnBackPressedDispatcherOwner provides dialog.asBackPressedDispatcherOwner
) {
    MainChatScreen(::dismiss)
}
Maybe @Ian Lake will tell me I missed something else, but in the meantime this seems to work 🤔
i

Ian Lake

05/23/2023, 4:09 PM
ComponentDialog already implements
OnBackPressedDispatcherOwner
as of Activity 1.5.0: https://developer.android.com/jetpack/androidx/releases/activity#1.5.0
And AppCompatDialog already extends from ComponentDialog as of AppCompat 1.5.0-alpha01: https://developer.android.com/jetpack/androidx/releases/appcompat#1.5.0-alpha01
And with this change, AppCompatDialog already sets the correct
ViewTreeOnBackPressedDispatcherOwner
on the returned dialog so that
LocalOnBackPressedDispatcherOwner
picks it up
And that change landed on March 16, so I'd expect it to be in the next AppCompat release (e.g., 1.7.0-alpha03)
In the mean time, I'd probably just set the ViewTreeOnBackPressedDispatcherOwner on your Dialog window's decorView
I assume you're already setting the ViewTreeLifecycleOwner and ViewTreeSavedStateRegistryOwner just to get your ComposeView to work in the BottomSheetDialog?
g

galex

05/24/2023, 8:29 AM
No I wasn't, and that's actually much better (no need to retain the dialog):
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return BottomSheetDialog(requireContext(), theme).apply {
            (...)
            initViewTreeOwners()
        }
    }
Here's it setting those itsefl:
private fun ComponentDialog.initViewTreeOwners() {
    window?.decorView?.let {
        it.setViewTreeLifecycleOwner(this)
        it.setViewTreeOnBackPressedDispatcherOwner(this)
        it.setViewTreeSavedStateRegistryOwner(this)
    }
}
Thanks for the whole explanation and update on AppCompat release, I will be able to remove this at some point!