How to use Multiple Bottom-sheets in Android Compose
Tags: android, kotlin, jetpackcompose
Published: 2021-05-07 12:53:36

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](https://media.giphy.com/media/mBQRMdEDMoKa9F7fvG/giphy.gif)

First before reading please be careful that this post applies to compose version `1.0.0-beta05`.
and is definitely related to these issues:
* [Integration Bottom sheets with navigation](https://issuetracker.google.com/issues/180247978)
* [composable dialog](https://issuetracker.google.com/issues/179608120)

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
```kotlin
sealed class BottomSheetScreen() {
    object Screen1: BottomSheetScreen()
    object Screen2: BottomSheetScreen()
    class Screen3(val argument:String):BottomSheetScreen()
}
```
**2**-  We will have a mutable state of our current sheet 
```kotlin
@Composable
private fun MainLayout() {
  var currentBottomSheet: BottomSheetScreen? by remember{
        mutableStateOf(null)
    }
}
``` 
**3**- We will use `BottomSheetScaffold` to handle opening and closing the bottom sheet
```kotlin
   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)
            }
    }
```
**4**- Now, We will define two lambdas for opening and closing the bottom sheet
```kotlin
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
```
Summing it up, our code should be similar to that
```kotlin
@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)
            }
    }
}
```

**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 
```kotlin
@Composable
fun SheetLayout(currentScreen: BottomSheetScreen,onCloseBottomSheet :()->Unit) {
    BottomSheetWithCloseDialog(onCloseBottomSheet){
        when(currentScreen){
            BottomSheetScreen.Screen1 -> Screen1()
            BottomSheetScreen.Screen2 -> Screen2()
            is BottomSheetScreen.Screen3 -> Screen3(argument = currentScreen.argument)
        }

    }
}
```

6- Finally last step we define `MainContent` composable function that takes `openSheet` as a parameter
```kotlin
@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")
        }
    }
}

```

**NB:** Here is the whole project used in the Demo on [Github](https://github.com/DavidIbrahim/MultipleBottomSheetsCompose)

Thanks for reading 🐱‍🏍