is there a way to receive a callback once a ModalB...
# compose
j
is there a way to receive a callback once a ModalBottomSheet animation has ended? my use case: I want to perform an action from my modal that sometimes results in a new navigation event. currently, the UX feels really odd when the modal hides and the new screen comes in.. I think I'd like to wait until the modal's hide() animation ends before I navigate to the next destination I can do this by simply using a non-blocking delay() before I navigate, but that feels like a big hack, and it requires me to know the animation duration, which isn't ideal. is there a proper way to achieve this?
j
You can listen to state changed of BottomSheetBehavior
j
☝️ that makes sense to me for reacting to the end of the animation, but I can't understand how I can work a solution like this into what I'm trying to do.. let me explain.. I have a search function which takes a string of a search term, and when the user finishes in the modal I want to do something like the following: 1. hide the modal 2. wait until the modal finishes animating out 3. call my function
search(searchTerm)
I understand part of your suggestion, but I can't understand how I will access the
searchTerm
, since these are in different scopes.. where the
searchTerm
is accessible, I cannot use
LaunchedEffect
since I'm not inside a Composable function I'm sure there will be a straightforward way to do this which I'm missing. any tips?
j
Depends on your architecture and setup🙂 Do I understand it right that the
searchTerm
is entered in the bottom sheet?
1
j
yeah that is correct, the user enters it inside the bottom sheet, and then the search button / IME search event looks like this:
Copy code
val validateThenSearch = {
    val searchTerm = searchFieldState.value.text.trim()
    if (searchTerm.isNotEmpty()) {
        focusManager.clearFocus(force = true)
        modalCoroutineScope.launch {
            searchModalState.hide()
        }
        // hack until we can correctly do this at end of animation
        screenCoroutineScope.launch {
            delay(250)
            search(searchTerm)
        }
    }
}
j
Gotcha! In that case, you don't need the effect.
snapshotFlow
works outside of composables, too. So something like:
Copy code
val validateThenSearch = {
    val searchTerm = searchFieldState.value.text.trim()
    if (searchTerm.isNotEmpty()) {
        focusManager.clearFocus(force = true)
        modalCoroutineScope.launch {
            // This is in a different coroutine than the hide call because hide can throw a CancellationException in some cases, but the sheet could still get hidden
            val sheetHiddenEvents = snapshotFlow { searchModalState.currentValue }.filter { it == ModalBottomSheetValue.Hidden }
            val waitForSheetHidden = sheetHiddenEvents.first()
            search(searchTerm)
        }
        modalCoroutineScope.launch {
            searchModalState.hide()
        }
    }
}
j
ahh that's a nice solution! thanks so much Jossi!
🎉 1