Is there a way to hoist the `ModalBottomSheetState` in the ViewModel ? For now we do some ugly synci...
a
Is there a way to hoist the
ModalBottomSheetState
in the ViewModel ? For now we do some ugly syncing with a vm state and the
ModalBottomSheetState
in the Composable
Copy code
val modalBottomSheetState =
        rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden, skipHalfExpanded = true)
    val isVisible by viewModel.isVisible.collectAsState()
    // if the bottom sheet state is changed by dragging down we need to sync it with our vm state
    // we have the state in the vm to control it from outside of the Composable
    LaunchedEffect(key1 = modalBottomSheetState.isVisible) {
        if (!modalBottomSheetState.isVisible && isVisible) viewModel.hide()
    }
    LaunchedEffect(key1 = isVisible) {
        when {
            isVisible -> modalBottomSheetState.show()
            else -> modalBottomSheetState.hide()
        }
    }
    return modalBottomSheetState
After updating Compose this results in a recompositon loop
đź‘€ 1
c
I always have this question and although I've gotten some pointers from either @jossiwolf or @Manuel Vivo I have never been actually been able to get it to work just right. I kinda just decided that maybe I shouldn't hoist that state. but saying that out loud... makes it sound dumb. of course you should be able to hoist it. subscribed. 🍿
m
I’m not convinced i would put this in the view model myself, but you can create the bottomSheetState yourself in your view model. You just can’t use “rememberModalBottomSheetState” since it wouldn’t created in composable code, and thus you can’t use “remember”. That responsibility is transfered to the vm and vm store instead.
Copy code
ModalBottomSheetState(
            initialValue = initialValue,
            animationSpec = animationSpec,
            isSkipHalfExpanded = skipHalfExpanded,
            confirmStateChange = confirmStateChange
        )
c
yeah, but i think you lose the ability to open and hide the bottom sheet in a VM if you do it that way
m
You can open and hide the bottom sheet in the VM but that needs to be triggered from a UI scope. It cannot be done with the
viewModelScope
. We documented the caveat here: https://developer.android.com/jetpack/compose/state-hoisting#caveat oYou can
What decides whether this should be in a ViewModel, a plain state holder class or just in the UI itself is the type of logic that involves that state. If the state is driven by business logic, then you can place it in a ViewModel. If it’s just UI logic, then plain class or the UI itself. The link I shared also talks about that
a
the docs get better and better ❤️ thanks a lot for the clarification 🙌
I assume in the example in the doc i could not call
closeDrawer
from a Fragment as i don't have the right uiScope there ? at least that is what happens when i pass a LifecycleScope from my Fragment
A MonotonicFrameClock is not available in this CoroutineContext
107 Views