Android

Jetpack Compose Basics - Looking for an alternative to menus or dialogues? Try the Modal Bottom Sheet

Bottom Sheet is component used as supplementary surface anchored to bottom of screen. This article will be about exact type of Bottom Sheet - Modal Bottom Sheet and how to use it in Jetpack Compose.

Peter Šuly13 Dec 2021

It's an alternative to menus or dialogs, it has to be dismissed (either by swipe or by some other user interaction) to interact with underlaying content of screen. In Jetpack Compose, bottom sheet is implemented via ModalBottomSheet composable.

Bottom sheet anatomy. 1 - bottom sheet content, 2 - row of bottom sheet, 3 - overlaid screen content

How to create Bottom Sheet in Jetpack Compose?

ModalBottomSheet has 3 possible state defined through sheetState parameter of type ModalBottomSheetValue. Possible values are Hidden, Expanded or HalfExpanded. Default value in sheet state is Hidden, own state can be remembered like this

val sheetState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)

ModalBottomSheet, as usual in Jetpack Compose, has many parameters for customisation, two of them are mandatory.

fun ModalBottomSheetLayout(
    sheetContent: @Composable ColumnScope.() -> Unit,
    modifier: Modifier = Modifier,
    sheetState: ModalBottomSheetState = rememberModalBottomSheetState(Hidden),
    sheetShape: Shape = MaterialTheme.shapes.large,
    sheetElevation: Dp = ModalBottomSheetDefaults.Elevation,
    sheetBackgroundColor: Color = MaterialTheme.colors.surface,
    sheetContentColor: Color = contentColorFor(sheetBackgroundColor),
    scrimColor: Color = ModalBottomSheetDefaults.scrimColor,
    content: @Composable () -> Unit
)

Mandatory parameters

  • sheetContent - composable, containing content of bottom sheet
  • content - composable, containing content of screen behind the bottom sheet. This content is overlayed by scrimColor when bottom sheet is in Expanded state

Optional parameters

  • sheetState - controls state of ModalBottomSheet
  • modifier - used for changes from the caller side
  • sheetShape - shape of bottom sheet e.g. *RoundedCornerShape*(topStart = 24.*dp*, topEnd = 24.*dp*)
  • sheetElevation - elevation of bottom sheet in dp
  • sheetBackgroundColor - background color of bottom sheet, defaultly set to surface color
  • sheetContentColor - content color contrasting on background color, default value is computed using contentColorFor function
  • scrimColor - color of overlay applied on content when bottom sheet is visible
Behaviour of bottom sheet

How to open ModalBottomSheet on Button click?

There are show() and hide() functions ready for animated transition of ModalBottomSheet which can be called on modalBottomSheetState. These are suspend functions, because animation run as coroutine, scope or LaunchedEffect is needed to use them.

val sheetState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)

Button(
    onClick = {
        scope.launch { 
						// Important part
            sheetState.show()  
        }
    },
    content = { ... }
)

How to disable Half Expanded state in ModalBottomSheet?

In some cases, HalfExpanded state is not desirable and luckily there is a way to disable it by returning false in confirmStateChange lambda.

val sheetState = rememberModalBottomSheetState(
    initialValue = ModalBottomSheetValue.Hidden,
    confirmStateChange = { it != ModalBottomSheetValue.HalfExpanded }
)

More articles from the Jetpack Compose Basics series:

Peter Šuly13 Dec 2021