https://kotlinlang.org logo
#compose
Title
# compose
j

james

02/17/2022, 9:07 AM
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

Javi Chaqués

02/17/2022, 9:39 AM
You can listen to state changed of BottomSheetBehavior
j

james

02/17/2022, 10:09 AM
☝️ 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

jossiwolf

02/17/2022, 5:11 PM
Depends on your architecture and setup🙂 Do I understand it right that the
searchTerm
is entered in the bottom sheet?
1
j

james

02/17/2022, 9:12 PM
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

jossiwolf

02/18/2022, 9:43 AM
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

james

02/20/2022, 4:18 AM
ahh that's a nice solution! thanks so much Jossi!
🎉 1