Android Compose ModalBottomSheetLayout outside click

1.7k Views Asked by At

I want to catch event when user clicks outside of ModalBottomSheetLayout. I wrapped ModalBottomSheetLayout with Box which is full size of the screen and set click listener. But Click listener only works when I click on the ModalBottomSheetLayout but not outside. I guess ModalBottomSheetLayout already consumes tap events and doesn't allow me to catch it?

Box(
    modifier = Modifier
        .clickable {
            Log.e("TAG", "clicked!")
        }.pointerInput(Unit) {
            detectTapGestures {
                Log.e("TAG", "tapped!")
            }
        }
        .fillMaxSize()
) {
    ModalBottomSheetLayout(
        sheetState = sheetState,
        sheetContent = {
            content()
        }
    )
}

Is there a way to catch the event of click/tap outside of ModalBottomSheetLayout?

2

There are 2 best solutions below

2
On BEST ANSWER

ModalBottomSheetLayout api doesn't allow you to catch this events, but you can do the following:

Box(
    modifier = Modifier
        .pointerInteropFilter {
            val bottomSheetShown = sheetState.currentValue != ModalBottomSheetValue.Hidden
            val outside = it.y < sheetState.offset.value

            if (bottomSheetShown && outside) {
                // do you own logic here
                Log.d("BottomSheet", "MotionEvent outside")
                true
            } else {
                false
            }
        }
) {
    ModalBottomSheetLayout(
        sheetContent = { BottomSheetContent() },
        content = { Screen(onShow = { coroutineScope.launch { sheetState.show() } }) },
        sheetState = sheetState,
    )
}

This way you will get all the MotionEvents inside of the if (bottomSheetShown && outside block. There you can process this events, do you business and after that ether pass it forward to the bottom sheet (by returning false) or block it (by returning true - then your bottom sheet will not get this events)

0
On
LaunchedEffect(sheetState.currentValue) {
    if (sheetState.currentValue == ModalBottomSheetValue.Hidden) {
       // Do work Here
    }
}

ModalBottomSheetLayout(
    sheetContent = { BottomSheetContent() },
    content = { Screen(onShow = { coroutineScope.launch { sheetState.show() } }) },
    sheetState = sheetState,
)

Whenever there is change in state of modal bottom sheet it will be listen by launchedEffect and trigger the logic that you want to perform.