Hey all, I've got a `BottomSheet` that sits above ...
# compose
t
Hey all, I've got a
BottomSheet
that sits above the
BottomAppBar
. As the sheet is expanded, I'd like the
BottomAppBar
to scroll off screen. I've managed to sort of achieve this by tying the `BottomAppBar's`y offset to the bottom sheet's offset amount (derived from
BottomSheetState
direction & progress:
Copy code
val bottomSheetScaffoldState = rememberBottomSheetScaffoldState()

Scaffold (
    bottomBar = {
        BottomAppBar(Modifier.offset(y = 56.dp * (1f - bottomSheetState.offsetFraction()))
    }
) { padding ->
    BottomSheetScaffold(Modifier.padding(bottom = 56.dp * bottomSheetState.offsetFraction()))
}
The problem is that the bottom sheet scroll/fling events now seem to be sort of interrupted. I guess having the padding change out from underneath it while it's scrolling causes issues with the size calculations or something along those lines. Just wondering if anyone can recommend an approach for this?
Here's the actual code if anyone is interested in replicating:
Copy code
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun Root() {

    Surface(
        modifier = Modifier.fillMaxSize(),
        color = MaterialTheme.colors.background
    ) {
        val bottomSheetScaffoldState = rememberBottomSheetScaffoldState()

        Scaffold(
            bottomBar = {
                BottomAppBar(
                    Modifier.offset(y = 56.dp * (1f - bottomSheetScaffoldState.bottomSheetState.offsetFraction()))
                ) {
                    AppBottomNavigation(
                        modifier = Modifier,
                        selected = false
                    ) {
                    }
                }
            }) {
            BottomSheetScaffold(
                modifier = Modifier.padding(bottom = 56.dp * (bottomSheetScaffoldState.bottomSheetState.offsetFraction())),
                sheetContent = {
                    Box(
                        Modifier
                            .fillMaxSize()
                            .background(MaterialColors.primary)
                    )
                },
                scaffoldState = bottomSheetScaffoldState
            ) { padding ->
                Box(
                    Modifier
                        .fillMaxSize()
                        .background(Color.Green.copy(alpha = 0.5f))
                )
            }
        }
    }
}

@OptIn(ExperimentalMaterialApi::class)
fun BottomSheetState.offsetFraction(): Float {
    var offsetFraction = progress.fraction

    if (direction == 0f) {
        offsetFraction = if (isExpanded) 0f else 1f
    }

    if (direction < 0) {
        offsetFraction = 1f - offsetFraction
    }

    return offsetFraction
}
z
Try using a
graphicsLayer
-based offset instead of a layout-based offset?
c
Someone had a similar thing they implemented I think fairly recently. Let me try to look it up.
t
Thanks. I'll have a look at
graphicsLayer
, and yeah that sounds like exactly the same problem!
OK, I managed to work this out. The key is to modify the
BottomSheetScaffold's
offset (so it moves down as the sheet scrolls up), and to modify the
BottomSheetScaffold.content{}
offset in the opposite direction. By modifying offset, rather than padding, you don't affect the size of the bottom sheet, and so it's not recomposed as you scroll, so scroll/fling events are not interrupted.
Copy code
@Composable
fun Root() {

    Surface(
        modifier = Modifier.fillMaxSize(),
        color = MaterialTheme.colors.background
    ) {
        val bottomSheetScaffoldState = rememberBottomSheetScaffoldState()

        Scaffold(
            bottomBar = {
                BottomAppBar(
                    modifier = Modifier
                        .offset(y = 56.dp * (1f - bottomSheetScaffoldState.bottomSheetState.offsetFraction())),
                    backgroundColor = MaterialColors.background
                ) {
                    AppBottomNavigation(
                        modifier = Modifier,
                        selected = false
                    ) {
                    }
                }
            }) {
            BottomSheetScaffold(
                modifier = Modifier
                    .offset(y = -(56.dp * (bottomSheetScaffoldState.bottomSheetState.offsetFraction()))),
                sheetContent = {
                    Box(
                        Modifier
                            .fillMaxSize()
                            .background(MaterialColors.primary)
                    )
                },
                scaffoldState = bottomSheetScaffoldState
            ) { padding ->
                Box(
                    Modifier
                        .padding(padding)
                        .offset(y = 56.dp * (bottomSheetScaffoldState.bottomSheetState.offsetFraction()))
                ) {
                    Library()
                }
            }
        }
    }
}
c
Looks very slick. @Doris Liu would be proud
😊 2