DEV Community

loading...
Cover image for How to use Multiple Bottom-sheets in Android Compose

How to use Multiple Bottom-sheets in Android Compose

davidibrahim profile image David ・Updated on ・3 min read

After trying to refactor my project from the normal view system to Android Compose, I can really feel the difference between them.

I feel Android Compose will for sure become the default way to build UI in native android, but it still have a lot of cons that Google engineers are trying to solve but till then, I am gonna write on how to solve one of them in this post and it is how to have multiple bottom-sheets in the same app.

After reading this article you will easily build multiple bottom sheets as shown below.
ss

First before reading please be careful that this post applies to compose version 1.0.0-beta05.
and is definitely related to these issues:

If these two issues are not solved yet you can continue reading my post, if any of them are solved and it will change the way to support multiple bottom-sheets, I will write another post.

1- Now Let's start by defining the bottom sheets that we are gonna use in our application

sealed class BottomSheetScreen() {
    object Screen1: BottomSheetScreen()
    object Screen2: BottomSheetScreen()
    class Screen3(val argument:String):BottomSheetScreen()
}
Enter fullscreen mode Exit fullscreen mode

2- We will have a mutable state of our current sheet

@Composable
private fun MainLayout() {
  var currentBottomSheet: BottomSheetScreen? by remember{
        mutableStateOf(null)
    }
}
Enter fullscreen mode Exit fullscreen mode

3- We will use BottomSheetScaffold to handle opening and closing the bottom sheet

   val scaffoldState = rememberBottomSheetScaffoldState()
   BottomSheetScaffold(sheetPeekHeight = 0.dp, scaffoldState = scaffoldState,
        sheetShape = BottomSheetShape,
        sheetContent = {
           currentBottomSheet?.let { currentSheet ->
                SheetLayout(currentSheet,closeSheet)
            }
        }) { paddingValues ->
            Box(Modifier.padding(paddingValues)){
                MainContent(openSheet)
            }
    }
Enter fullscreen mode Exit fullscreen mode

4- Now, We will define two lambdas for opening and closing the bottom sheet

val closeSheet: () -> Unit = {
        scope.launch {
            scaffoldState.bottomSheetState.collapse()

        }
    }


    val openSheet: (BottomSheetScreen) -> Unit = {
        currentBottomSheet = it
        scope.launch { scaffoldState.bottomSheetState.expand() }

    }
    // to set the current sheet to null when the bottom sheet closes
    if(scaffoldState.bottomSheetState.isCollapsed)
        currentBottomSheet = null
Enter fullscreen mode Exit fullscreen mode

Summing it up, our code should be similar to that

@OptIn(ExperimentalMaterialApi::class)
@Composable
private fun MainLayout() {
    val scope = rememberCoroutineScope()
    val scaffoldState = rememberBottomSheetScaffoldState()
    var currentBottomSheet: BottomSheetScreen? by remember{
        mutableStateOf(null)
    }

    val closeSheet: () -> Unit = {
        scope.launch {
            scaffoldState.bottomSheetState.collapse()
        }
    }


    val openSheet: (BottomSheetScreen) -> Unit = {
        currentBottomSheet = it
        scope.launch { scaffoldState.bottomSheetState.expand() }

    }
  if(scaffoldState.bottomSheetState.isCollapsed)
        currentBottomSheet = null

    BottomSheetScaffold(sheetPeekHeight = 0.dp, scaffoldState = scaffoldState,
        sheetShape = BottomSheetShape,
        sheetContent = {
          currentBottomSheet?.let { currentSheet ->
                SheetLayout(currentSheet,closeSheet)
            }
        }) { paddingValues ->
            Box(Modifier.padding(paddingValues)){
                MainContent(openSheet)
            }
    }
}
Enter fullscreen mode Exit fullscreen mode

5- Now we will define our SheetLayout, as we can see from the above code that it takes two parameters

  • The current bottom sheet
  • The closeSheet lambda, because if we want to have a button to close the sheet

It should be similar to that

@Composable
fun SheetLayout(currentScreen: BottomSheetScreen,onCloseBottomSheet :()->Unit) {
    BottomSheetWithCloseDialog(onCloseBottomSheet){
        when(currentScreen){
            BottomSheetScreen.Screen1 -> Screen1()
            BottomSheetScreen.Screen2 -> Screen2()
            is BottomSheetScreen.Screen3 -> Screen3(argument = currentScreen.argument)
        }

    }
}
Enter fullscreen mode Exit fullscreen mode

6- Finally last step we define MainContent composable function that takes openSheet as a parameter

@Composable
fun MainContent(openSheet: (BottomSheetScreen) -> Unit) {
    Column(Modifier.fillMaxSize(),verticalArrangement = Arrangement.SpaceEvenly,horizontalAlignment = Alignment.CenterHorizontally) {
        Text(text = "This is Main Content")
        Button(onClick = { openSheet(BottomSheetScreen.Screen1) }) {
            Text(text = "Open bottom sheet 1")
        }

        Button(onClick = { openSheet(BottomSheetScreen.Screen2) }) {
            Text(text = "Open bottom sheet 2")
        }
        Button(onClick = { openSheet(BottomSheetScreen.Screen3("this is an argument")) }) {
            Text(text = "Open bottom sheet 2")
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

NB: Here is the whole project used in the Demo on Github

Thanks for reading πŸ±β€πŸ

Discussion (2)

Collapse
uwaisalqadri profile image
Collapse
martinaihab profile image
Martina Ihab

Impressive πŸ‘ŒπŸ»

Forem Open with the Forem app