rysv
rysv

Reputation: 3460

Jetpack Compose FloatingActionButton partially hidden when used in BottomSheetScaffold

In bottom-sheet collapsed mode, half of FAB is hidden. Here is the code. If I just use Scaffold this issue is not present.

class MainActivity : ComponentActivity() {
    @ExperimentalMaterialApi
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ScaffTestTheme {
                val bottomSheetScaffoldState = rememberBottomSheetScaffoldState(
                    bottomSheetState = BottomSheetState(BottomSheetValue.Collapsed)
                )
                val scope = rememberCoroutineScope()

                BottomSheetScaffold(
                    scaffoldState = bottomSheetScaffoldState,
                    sheetContent = {
                        Text("Hello", modifier = Modifier.padding(20.dp))
                    },
                    sheetPeekHeight = 0.dp,
                    floatingActionButton = {
                        FloatingActionButton(onClick = {}) {
                            Icon(Icons.Filled.Add, contentDescription = "Add")
                        }
                    }
                ) {
                    TextButton(onClick = {
                        scope.launch {
                            if (bottomSheetScaffoldState.bottomSheetState.isCollapsed) {
                                bottomSheetScaffoldState.bottomSheetState.expand()
                            } else {
                                bottomSheetScaffoldState.bottomSheetState.collapse()
                            }
                        }
                    }) {
                        Text("Toggle")
                    }
                }
            }
        }
    }
}

I see it like this:

Upvotes: 3

Views: 3261

Answers (3)

z.g.y
z.g.y

Reputation: 6277

In addition to provided answers, you may consider this one.

This is a bit tedious since with this approach, you have to

  • set the sheetPeekHeight both for the scaffold and as a top padding to the sheet content
  • set the sheetBackgroundColor the same color with the content{…} background color
  • set the sheetElevation to 0.dp to hide the edge border of the bottom sheet when you modify the background colors
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun SampleBottomSheet() {

    val contentBackground = Color.White
    val sheetPeekHeight = 40.dp
    val bottomSheetScaffoldState = rememberBottomSheetScaffoldState(
        bottomSheetState = BottomSheetState(BottomSheetValue.Collapsed)
    )

    val coroutineScope = rememberCoroutineScope()

    BottomSheetScaffold(
        scaffoldState = bottomSheetScaffoldState,
        sheetBackgroundColor = contentBackground,
        sheetElevation = 0.dp,
        sheetPeekHeight = sheetPeekHeight,
        sheetContent = {
            Column(
                modifier = Modifier
                    .padding(top = sheetPeekHeight)
                    .wrapContentHeight()
                    .fillMaxWidth()
                    .background(Color.DarkGray)
            ) {

                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(30.dp)
                        .background(Color.DarkGray)
                )

                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(80.dp)
                        .background(Color(0xFF4fc992))
                )
            }
        },
        floatingActionButton = {
            FloatingActionButton(
                backgroundColor = Color(0xFF4a6ebd),
                shape = CircleShape,
                onClick = {},
            ) {
                Icon(imageVector = Icons.Filled.Add, contentDescription = "icon")
            }
        }
    ) {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(contentBackground)
        ) {
            Button(
                onClick = {
                    coroutineScope.launch {
                        if (bottomSheetScaffoldState.bottomSheetState.isCollapsed) {
                            bottomSheetScaffoldState.bottomSheetState.expand()
                        } else {
                            bottomSheetScaffoldState.bottomSheetState.collapse()
                        }
                    }
                }
            ) {
                Text("Open/Close bottom sheet")
            }
        }
    }
}

Call-site usage:

class BottomSheetScaffoldExampleActivity: ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            SampleBottomSheet()
        }
    }
}

enter image description here

All these codes are copy-and-paste-able.

Upvotes: 1

Michael Krussel
Michael Krussel

Reputation: 2656

It seems like BottomSheetScaffold is designed to always have part of the sheet visible and the FAB partly overlapping it. This wasn't the behavior I wanted, and it doesn't seem to be what you wanted. Could use a BottomDrawerModal, but I don't want it to be modal.

I used a custom layout to lay the FAB half its height above where the scaffold lays it out.

val floatingActionButton = FloatingActionButton(onClick = {}) {
    Icon(Icons.Filled.Add, contentDescription = "Add")
}

BottomSheetScaffold(
    scaffoldState = bottomSheetScaffoldState,
    sheetContent = {
        Text("Hello", modifier = Modifier.padding(20.dp))
    },
    sheetPeekHeight = 0.dp,
    floatingActionButton = {
        Layout(content = floatingActionButton) { measurables, constraints ->
            val placeable = measurables.first().measure(constraints)

            layout(placeable.width, placeable.height) {
                placeable.placeRelative(0, -placeable.height / 2)
            }
        }
    }

) {
    TextButton(onClick = {
        scope.launch {
            if (bottomSheetScaffoldState.bottomSheetState.isCollapsed) {
                bottomSheetScaffoldState.bottomSheetState.expand()
            } else {
                bottomSheetScaffoldState.bottomSheetState.collapse()
            }
        }
    }) {
        Text("Toggle")
    }
}

Upvotes: 3

Jéluchu
Jéluchu

Reputation: 494

@srvy I have encountered the same problem as you, and after some research and looking at the components of BottomSheetScaffold, I have managed to find a solution.

Add inside your BottomSheetScaffold the following parameters:

  • sheetElevation = 0.dp
  • sheetPeekHeight = 40.dp (default 56.dp)
  • sheetBackgroundColor = Color.Transparent

You can edit sheetPeekHeight to vary the distance of the FloatingActionButton, the other two do not. Inside your code it would look like this:

BottomSheetScaffold(
    sheetElevation = 0.dp,
    sheetPeekHeight = 40.dp,
    sheetBackgroundColor = Color.Transparent,
    scaffoldState = bottomSheetScaffoldState,
    sheetContent = {
       Text("Hello", modifier = Modifier.padding(20.dp))
    },
    sheetPeekHeight = 0.dp,
    floatingActionButton = {
       FloatingActionButton(onClick = {}) {
          Icon(Icons.Filled.Add, contentDescription = "Add")
       }
    }
)

Upvotes: 2

Related Questions