« Bottom Sheet in Jetpack Compose.

Two types of Bottom Sheet

If you want to implement a standard bottom sheet, you can use the BottomSheetScaffold composable. It accepts similar parameters to Scaffold, such as topBar, floatingActionButton, and snackbarHost. It includes additional parameters that provide a means to display bottom sheets.

If you want to implement a modal bottom sheet, you can use the ModalBottomSheetLayout composable:

standard bottom sheet

1@OptIn(ExperimentalMaterialApi::class)
2@Composable
3fun HomeScreen() {
4 val bottomSheetScaffoldState =
5 rememberBottomSheetScaffoldState(bottomSheetState = BottomSheetState(BottomSheetValue.Collapsed))
6 val coroutineScope = rememberCoroutineScope()
7 BottomSheetScaffold(scaffoldState = bottomSheetScaffoldState, sheetContent = {
8 Box(
9 Modifier
10 .fillMaxWidth()
11 .height(200.dp)
12 ) {
13 Text(text = "Hello from sheet")
14 }
15 }, sheetPeekHeight = 0.dp) {
16 Button(onClick = {
17 coroutineScope.launch {
18 if (bottomSheetScaffoldState.bottomSheetState.isCollapsed) {
19 bottomSheetScaffoldState.bottomSheetState.expand()
20 } else {
21 bottomSheetScaffoldState.bottomSheetState.collapse()
22 }
23 }
24 }) {
25 Text(text = "Expand/Collapse Bottom Sheet")
26 }
27 }
28}

First, we define bottomSheetScaffoldState which will hold the state of BottomSheetScaffold. In turn it holds drawerState, bottomSheetState, snackbarHostState. In this tutorial, we focus only on bottomSheetState

sheetContent — defines the content of our Bottom Sheet. You put any composable you want.

sheetPeekHeight — sets the peek height of the Bottom Sheet. We will use 0.dp to hide the Bottom Sheet when the app starts.

So to interact with Bottom Sheet, we just must use these methods:

bottomSheetScaffoldState.bottomSheetState.expand() — to expand

bottomSheetScaffoldState.bottomSheetState.collapse() — to collapse

But these methods are suspend functions and that’s why they must be used in CoroutineScope.

For this purpose we can use rememberCoroutineScope to create coroutineScope

modal bottom sheet

1@OptIn(ExperimentalMaterialApi::class)
2@Composable
3fun MainScreen() {
4 val sheetState = rememberModalBottomSheetState(
5 initialValue = ModalBottomSheetValue.Hidden,
6 )
7 val coroutineScope = rememberCoroutineScope()
8
9 BackHandler(sheetState.isVisible) {
10 coroutineScope.launch { sheetState.hide() }
11 }
12
13 ModalBottomSheetLayout(
14 sheetState = sheetState, sheetContent = {
15 Column() {
16 BottomSheet()
17 BottomSheet()
18 BottomSheet()
19 BottomSheet()
20 }
21 }, modifier = Modifier.fillMaxSize()
22 ) {
23 Column(
24 modifier = Modifier
25 .fillMaxWidth()
26 .padding(top = 24.dp)
27 .padding(horizontal = 24.dp),
28 horizontalAlignment = Alignment.CenterHorizontally
29 ) {
30 Text(
31 text = "Welcome to bottom sheet playground!",
32 modifier = Modifier.fillMaxWidth(),
33 style = MaterialTheme.typography.h4,
34 textAlign = TextAlign.Center
35 )
36 Spacer(modifier = Modifier.height(32.dp))
37 Button(onClick = {
38 coroutineScope.launch {
39 if (sheetState.isVisible) sheetState.hide()
40 else sheetState.show()
41 }
42 }) {
43 Text(text = "Click to show bottom sheet")
44 }
45 }
46 }
47}
48
49@Composable
50fun BottomSheet() {
51 Column(
52 modifier = Modifier.padding(32.dp)
53 ) {
54 Text(
55 text = "Bottom sheet",
56 style = MaterialTheme.typography.h6
57 )
58 Spacer(modifier = Modifier.height(32.dp))
59 Text(
60 text = "Click outside the bottom sheet to hide it",
61 style = MaterialTheme.typography.body1
62 )
63 }
64}

There are three ModalBottomSheetValues:

  1. Hidden
  2. Expanded
  3. HalfExpanded

The first two are describing enough. HalfExpanded will only show half of the bottom sheet, and this state is enabled only if the height of the bottom sheet is more than 50% of the screen height.

As we can see, we put our screen composables inside the ModalBottomSheetLayout’s content. Also, we pass sheetState as an argument.

BackHandler is an effect for handling presses of the system back button. The first argument is when it is enabled, and the second is what it should do when the system back button is pressed.

Button inside the Column is showing and hiding the bottom sheet. sheetState.show() will show the bottom sheet with animation and sheetState.hide() will hide the bottom sheet with animation.

The logic for showing and hiding the bottom sheet is put in the UI, but it should be handled by the ViewModel.

For full class code to try out the code yourself:

https://github.com/anishakd4/JetpackComposeBottomSheet