5

How can i achieve callback/listener mechanism on JetPack Compose BottomSheet state changes?

Something similar to:

   @Override  
   public void onStateChanged(@NonNull View bottomSheet, int newState) {  
     if (newState == BottomSheetBehavior.STATE_COLLAPSED && mIsCollapsedFromBackPress){
        
     }
   }  

  @Override  
  public void onSlide(@NonNull View bottomSheet, float slideOffset) {  
  }  
});

As we used to do in Java/Kotlin.

Right now I am passing this as lambda to another composable from where the bottomsheet needs to be closed.

    val closeSheet: () -> Unit = {
        scope.launch {
            modalState.hide()
        }
    }

But i want to get the callback that the bottomsheet has been fully collapsed and I can continue my task.

Actual issue i am facing: I am converting a composable to bitmap on a button click. The button is inside the BottomSheet and the composable that needs to be converted is behind the BottomSheet. So, sometimes the bottomsheet also appears in the bitmap. I want to trigger the process only if the bottomsheet is fully collpased.

I found this answer on SO, but still the issue is about the callback. Not sure how to use it.

ankuranurag2
  • 2,300
  • 15
  • 30
  • Could you explain what's unclear in my answer? If you try to run the sample code you should see the logs according to the current state. – Phil Dukhov Nov 01 '21 at 09:30
  • @PhilipDukhov i want to execute my code only if the state is Hidden on a button click. Not in all cases. Also, if I make the state hidden, the bottom sheet takes few milliseconds to completely hide. Meanwhile my next line of code is executed as `state.hide()` is `suspended` method. There some portion of bottomsheet still appears in the converted bitmap. – ankuranurag2 Nov 01 '21 at 09:58
  • You don't have to use all the code, this sample demonstrates different ways of handling it, you can pick the one you need. `LaunchedEffect` should work here, just check your needed state with `if` statement. – Phil Dukhov Nov 01 '21 at 10:14

1 Answers1

15

You can use snapshotFlow, refer to this. It Creates a Flow from observable Snapshot state. Here is a sample code

    // State change callback
    LaunchedEffect(sheetState) {
        snapshotFlow { sheetState.isVisible }.collect { isVisible ->
            if (isVisible) {
                // Sheet is visible
            } else {
                // Not visible
            }
        }
    }

You can use this snapshotFlow for other things too for example Pager page change callback

    // Page change callback
    LaunchedEffect(pagerState) {
        snapshotFlow { pagerState.currentPage }.collect { page ->
            when (page) {
                0 -> // First page
                1 -> // Second page
                else -> // Other pages
            }
        }
    }
Enes Kayıklık
  • 351
  • 5
  • 12