androidandroid-jetpack-composeandroid-jetpack-compose-material3

How to disable BottomSheetScaffold Bounce/Jump effect when sheet is full expanded


I am using BottomSheetScaffold in one of my projects and I just put some content in the bottom sheet but when I swipe up on the expanded sheet, the sheet jumps/bounces, revealing the content of background.

Is there a way to remove this effect In BottomSheetScaffold? When it is expanded, swipe should not bounce the bottom sheet

A visual representation is attached below:

enter image description here

Code in question (please ignore custom theme values) :

val scaffoldState = rememberBottomSheetScaffoldState()
var currentSheetStat by remember { mutableStateOf(SheetContent.BookingRide) }
var sheetPeekHeight by remember {
    mutableStateOf(420.dp)
}
BottomSheetScaffold(
    scaffoldState = scaffoldState,
    modifier = Modifier.fillMaxSize(),
    sheetPeekHeight = sheetPeekHeight,
    sheetShadowElevation = 0.dp,
    sheetTonalElevation = 0.dp,
    containerColor = Color.Transparent,
    sheetContent = {

        Column {
            Column(
                Modifier
                    .padding(
                        start = BnTheme.gaps.component,
                        end = BnTheme.gaps.component,
                        bottom = BnTheme.gaps.component
                    )
                    .fillMaxWidth())
            {
                Row(verticalAlignment = Alignment.CenterVertically) {
                    if(currentSheetStat == SheetContent.RideStarted) {
                        BnPebbleMedium(pebbleText = stringResource(id = commonR.string.sos),
                            hasLeadingIcon = true, leadingIcon = painterResource(id = commonR.drawable.ic_alert_badge),
                            leadingIconTint = BnTheme.colors.error, pebbleTextColor = BnTheme.colors.error,
                            pebbleContainer = BnTheme.colors.surfaceContainer)
                    }
                    Spacer(modifier = Modifier.weight(1f))
                    Card(
                        shape = RoundedCornerShape(100),
                        colors = CardDefaults.cardColors(
                            containerColor = BnTheme.colors.surfaceContainer
                        ),
                        modifier = Modifier
                            .size(48.dp)
                    ) {
                        Column(horizontalAlignment = Alignment.CenterHorizontally,
                            verticalArrangement = Arrangement.Center,
                            modifier = Modifier.fillMaxSize()) {
                            Icon(
                                painter = painterResource(id = commonR.drawable.ic_locate),
                                contentDescription = null, Modifier.size(24.dp),
                                tint = shades_dark_blue_0
                            )
                        }

                    }
                }

            }

            Card(
                Modifier
                    .fillMaxWidth()
                    .background(Color.Transparent),
                shape = RoundedCornerShape(topStart = BnTheme.cornerRadius.crL, topEnd = BnTheme.cornerRadius.crL),
                colors = CardDefaults.cardColors(
                    containerColor = BnTheme.colors.surfaceContainer
                ),
                elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
            ) {

                AnimatedContent(
                    targetState = currentSheetStat,
                    label = "",
                ) {
                    Crossfade(targetState = it, label = "bottom sheet animation") {
                        when(it) {
                            SheetContent.BookingRide ->  {
                               //not important
                            }
                            SheetContent.ConfirmPickupLocation -> {
                                //not important
                            }
                            SheetContent.SendingRequest -> {
                                sheetPeekHeight = 220.dp
                                SheetContentSendingRequest{
                                    currentSheetStat = SheetContent.NavigatorArrival
                                }
                            }
                            SheetContent.NavigatorArrival -> {
                                // not important
                            }
                            SheetContent.RideStarted -> {
                                //not important
                            }
                        }
                    }
                }

            }
        }

    },
    sheetContainerColor = Color.Transparent,
    sheetDragHandle = {
        HorizontalDivider(thickness = 0.dp,
            color = Color.Transparent)
    }
    ) {

    Box(modifier = Modifier.fillMaxSize()) {
        ScreenContent() // the background map implementation
    }
}

And this is the Sheet content

@Composable
fun SheetContentSendingRequest( onRideRequestSent : () -> Unit ) {
Column(modifier = Modifier
    .fillMaxWidth()
    .padding(
        horizontal = BnTheme.gaps.component,
        vertical = BnTheme.gaps.element
    ))
{

    SheetDragHandle()

    Spacer(modifier = Modifier.height(BnTheme.gaps.component))

    Column (
        Modifier
            .padding(vertical = BnTheme.gaps.element)
            .fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally){
        BnText(
            text = stringResource(id = commonR.string.sent_ride_request),
            style = BnTheme.typography.titleSmallSemiBold,
            color = BnTheme.colors.bodyPrimary
        )

        Row {
            Row {
                BnText(
                    text = stringResource(commonR.string.you_will_reach_destination_by),
                    style = BnTheme.typography.bodyMediumMedium,
                    color = BnTheme.colors.bodySecondary
                )
                Spacer(modifier = Modifier.height(BnTheme.gaps.mini))

                BnText(
                    text = "11:11 AM",
                    style = BnTheme.typography.bodyMediumMedium,
                    color = BnTheme.colors.link
                )
            }
        }
    }

    Spacer(modifier = Modifier.height(BnTheme.gaps.component))

    Row {
        LinearProgressIndicator(
            progress = 1f,
            trackColor = BnTheme.colors.primaryButtonOff,
            color = BnTheme.colors.primaryButtonOn,
            modifier = Modifier
                .weight(1f)
                .padding(horizontal = 12.dp)
                .clip(RoundedCornerShape(100))
        )


        LinearProgressIndicator(
            progress = 0f,
            trackColor = BnTheme.colors.primaryButtonOff,
            color = BnTheme.colors.primaryButtonOn,
            modifier = Modifier
                .weight(1f)
                .padding(horizontal = 12.dp)
                .clip(RoundedCornerShape(100))


        )

        LinearProgressIndicator(
            progress = 0f,
            trackColor = BnTheme.colors.primaryButtonOff,
            color = BnTheme.colors.primaryButtonOn,
            modifier = Modifier
                .weight(1f)
                .padding(horizontal = 12.dp)
                .clip(RoundedCornerShape(100))

        )

        LinearProgressIndicator(
            progress = 0f,
            trackColor = BnTheme.colors.primaryButtonOff,
            color = BnTheme.colors.primaryButtonOn,
            modifier = Modifier
                .weight(1f)
                .padding(horizontal = 12.dp)
                .clip(RoundedCornerShape(100))


        )
    }

    Spacer(modifier = Modifier.height(BnTheme.gaps.component))

    Icon(painter = painterResource(id = commonR.drawable.vector_shared_ride), contentDescription = null,
        tint = Color.Unspecified, modifier = Modifier
            .height(124.dp)
            .align(Alignment.CenterHorizontally)
            .noRippleClickable { onRideRequestSent() })
    Spacer(modifier = Modifier.height(BnTheme.gaps.component))


}

}


Solution

  • This is probably not intended behavior, so you can consider opening an issue on the Google Issue Tracker so that the Android Developer Team can take a look at this. I can however present you a workaround.

    I found that the sheetPeekHeight parameter of the BottomSheetScaffold Composable plays an important role. My guess is that you have set it to 0.dp. If you set the sheetPeekHeight to 10.dp, the BottomSheet will have a rectangular Composable with 10dp height at the bottom area behind the BottomSheet.

    You can use this behavior to cover the Scaffold background when swiping up. Please update your Composable as follows:

    val scaffoldState = rememberBottomSheetScaffoldState()
    val bottomSheetState = scaffoldState.bottomSheetState  // just for convenience
    
    BottomSheetScaffold(
        scaffoldState = scaffoldState,
        sheetPeekHeight = 
            if (bottomSheetState.currentValue == SheetValue.Expanded &&
                bottomSheetState.targetValue == SheetValue.Expanded) {
                50.dp
            } else {
                0.dp
            },
        sheetContent = {
            //...
        }
    ) {
        //...
    }
    

    With this code, when the BottomSheet is expanded, we temporarily set the sheetPeekHeight to 50dp to cover up the Scaffold background when swiping up.

    Note however the limitation that when you positioned elements relatively in your Scaffold (for example by using a Column with verticalArrangement), these elements will move, as the size of the Scaffold content is temporarily decreased when the BottomSheet is expanded.


    In your case, sheetContainerColor = Color.Transparent causes the problematic behavior. The only workaround that comes to my mind is to manually display a background overlay behind the BottomSheet. You can try it as follows:

    Box(modifier = Modifier.fillMaxSize()) {
        ScreenContent() // the background map implementation
        Row(
            modifier = Modifier
               .align(Alignment.BottomCenter)
               .fillMaxWidth()
               .height(sheetPeekHeight - 25.dp)
               .background(BnTheme.colors.surfaceContainer)
        )
    }
    

    However, your code is a little bit strange. To expand or collapse a BottomSheet, you should use

    instead of modifying the sheetPeekHeight. Also have a look at the official documentation.