Is there a way to dismiss a `SheetState` such that...
# compose
z
Is there a way to dismiss a
SheetState
such that onDismiss is invoked when the animation is finished? Example code in 🧵
Im doing the following currently. It works, but I dont like having magic numbers in there 😱 Without the delay, the sheet is removed a bit abruptly. scope.launch { state.hide() delay(150) // exactly what my onDismiss function does emitter emit Dismissed }
s
Which sheet are you using? The material(3?) sheets mark the hide() function as suspending, which means that when the coroutine resumes after it’s done with hide() it really should’ve been done with the animation already, have you found this not to be the case for you?
https://cs.android.com/androidx/platform/tools/dokka-devsite-plugin/+/master:testDat[…]3?q=androidx.compose.material3.samples.ModalBottomSheetSample This also shows an example of them doing this, letting the hide() finish, and then dismissing the dialog completely by setting the state to false too.
z
Yup, thats exactly what Im seeing. Thanks for the link - Ill try using invokeOnCompletion on the job, the timing is just off by ~100 ms so maybe that works? Ill report back!
Muy buen, that works better. Thank you! I do wonder if this is worth reporting? Seems more like a workaround using invokeOnCompletion than placing the logic right after .hide since its suspending.
s
The thing is, this
Copy code
launch {
  someSuspendFunction()
  yourCallback()
}
should really be the exact same thing as
Copy code
launch {
  someSuspendFunction()
}.invokeOnCompletion {
  yourCallback()
}
since the coroutine should suspend inside hide() until it’s properly done.
So yeah it certainly feels super odd that it’s any different in your case 😵‍💫
Is the coroutine scope grabbed simply using
rememberCoroutineScope
?
z
Yup!
s
Suuuper odd
I really can’t think of a reason why that’d be the case. Which sheet is it that you’re using then? Maybe the hide() implementation is broken for what you’re using?
Returns too early?
z
0,00001% chance that my debug build is actually the culprit
s
Or you got some other part in the code which listens to the state change and triggers the callback too early
0,00001% chance that my debug build is actually the culprit
Always possible 😅
z
Dang it, Ill have to test with a release build.. Brb
s
Haha sorry for doing this to you 🫣
z
As it turns out, I just dont like the hide animation of the sheet. The delay I was using was just placebo, it doesnt really do any difference 😅 The default animation is
val AnimationSpec = SpringSpec<Float>()
and it makes me wonder if the lack of visibilityThreshold is causing the sheet to hide prematurely. Ill have to test this further before I can say for sure.
s
Heh alright, nice to see it’s not a flat out bug though. Lmk if it works out well for you after all
Oh I think I understand why they do the invokeOnCompletion in that code. The coroutine may be cancelled somehow in the meantime as it’s doing the
hide()
call. If you do the cleanup after it it won’t ever run in case of cancellation I don’t think. With the completion callback it should run always. So I think that’s why they do it, not for any timing issues.
j
Yes, keep in mind that
hide()
or
show()
can be cancelled and would throw a
CancellationException
in that case.
invokeOnCompletion
vs try-catch doesn't make a difference in this case 🙂
z
It would be detrimental for hide to do its thing, but the onDismiss not coming through - basically making the UI "under" the sheet unresponsive, so that makes sense.
s
invokeOnCompletion
vs try-catch
Yeah I was comparing it with this, which would in fact be wrong right? The first option would not work properly in case of cancellation
j
Yes, the job would be cancelled if
someSuspendFunction()
throws and
yourCallback()
never executed
e
Narrator: Foot, meet Gun