Alexander Tumanin
Alexander Tumanin

Reputation: 1842

Jetpack compose snackbar hidden behind bottomsheet

I show a SnackBar inside Scaffold like this:

val scaffoldState = rememberScaffoldState()

LaunchedEffect(offerViewModel.onAddToCartError) {
    offerViewModel.onAddToCartError = {
        coroutineScope.launch {
            scaffoldState.snackbarHostState.showSnackbar(
                message = message
            )
        }
    }
}
Scaffold(
    Modifier.nestedScroll(nestedScrollConnection),
    scaffoldState = scaffoldState,
    snackbarHost = {
        SnackbarHost(it) { data ->
            ErrorSnackBar(
                message = data.message,
                fontSize = 16.sp
            )
        }
    }) { paddingValues ->
    Box(
        modifier = Modifier
            .padding(paddingValues)
            .fillMaxSize()
    ) {
        //content
        // full screen ModalBottomSheet
        if (showBottomSheet) {
            ModalBottomSheet(
                modifier = modifier,
                windowInsets = WindowInsets(
                    bottom = bottomInsets.getBottom(density).pxToDp().dp,
                    top = topInsets.getTop(density).pxToDp().dp
                )
            ){...}
        }
    }
}

but if the ModalBottomSheet is shown, it covers my SnackBar. How can I show the SnackBar over all content including bottom sheets on my screen?

Upvotes: 4

Views: 2347

Answers (3)

javaxian
javaxian

Reputation: 2394

Using a Popup to show anything on top of a ModalBottomSheet didn't work for me. Compose's ModalBottomSheet is displayed using a window on Android, so it's outside of the Compose-created view tree. To overlay anything on top of it, you need another window that is added after the bottom sheet is displayed. Compose's Dialog is implemented as a window in Android, so you can use it for that purpose, making sure that it takes the whole screen if needed and it passes touch and focus events down to anything that's below it. Here's my code:

        Dialog(
            onDismissRequest = {},
            properties = DialogProperties(
                dismissOnClickOutside = false,
                dismissOnBackPress = false,
                usePlatformDefaultWidth = false
            )
        ) {
            (LocalView.current.parent as DialogWindowProvider).window.apply {
                setDimAmount(0f)
                addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
                addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
            }

            // your Composable here

        }

My answer is based on a post that helped me tremendously to get it right after lots of googling.

Upvotes: 0

maqsats
maqsats

Reputation: 358

You can cover with Popup() to show it over Dialog or ModalBottomSheet.

This has not built-in support for avoiding the IME (software keyboard), you can follow https://stackoverflow.com/a/75512140/12693743 to make it fully work.

    SnackbarHost(LocalSnackBarHostState.current) {
        Popup(
            alignment = Alignment.TopCenter,
            onDismissRequest = {
                it.dismiss()
            }
        ) {
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .noRippleClickable {
                        it.dismiss()
                    },
                contentAlignment = Alignment.TopCenter
            ) {
                Snackbar() // your implementation of Snackbar
            }
        }
    }

Upvotes: 4

Murad Eliyev
Murad Eliyev

Reputation: 120

You need to use BottomSheetScaffold.

Upvotes: 0

Related Questions