Jetpack Composeにおけるボトムシート

### ModalBottomSheetLayout

https://developer.android.com/reference/kotlin/androidx/compose/material/package-summary#ModalBottomSheetLayout(kotlin.Function1,androidx.compose.ui.Modifier,androidx.compose.material.ModalBottomSheetState,kotlin.Boolean,androidx.compose.ui.graphics.Shape,androidx.compose.ui.unit.Dp,androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Color,kotlin.Function0)

`androidx.compose.material`用のボトムシートとして用意されているコンポーザブルです。
ScaffoldやBoxなど通常で画面に表示される要素をwrapします。
rememberModalBottomSheetState()でボトムシートの状態を作っています。
initialValueでModalBottomSheetValue.Hiddenを指定して隠れた状態にしておき、skipHalfExpandedで中間状態（ボトムシートで画面の一部が隠された状態）にできるかどうかを指定しています。
開閉アクションがのshowとhideがsuspend関数なのでrememberCoroutineScope()でscope変数を作る必要があります。
sheetContentにボトムシートで表示される内容を指定します。
フルモーダル表示にするには内部のコンテンツにModifier.fillMaxSize()を指定すると良いです。

```ModalBottomSheetLayout.kt
var skipHalfExpanded by remember { mutableStateOf(false) }
val state =
    rememberModalBottomSheetState(
        initialValue = ModalBottomSheetValue.Hidden,
        skipHalfExpanded = skipHalfExpanded
    )
val scope = rememberCoroutineScope()
ModalBottomSheetLayout(
    sheetState = state,
    sheetContent = {
        LazyColumn {
            items(50) {
                ListItem(
                    text = { Text("Item $it") },
                    icon = {
                        Icon(
                            Icons.Default.Favorite,
                            contentDescription = "Localized description"
                        )
                    }
                )
            }
        }
    }
) {
    Column(
        modifier = Modifier.fillMaxSize().padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Row(
            Modifier.toggleable(
                value = skipHalfExpanded,
                role = Role.Checkbox,
                onValueChange = { checked -> skipHalfExpanded = checked }
            )
        ) {
            Checkbox(checked = skipHalfExpanded, onCheckedChange = null)
            Spacer(Modifier.width(16.dp))
            Text("Skip Half Expanded State")
        }
        Spacer(Modifier.height(20.dp))
        Button(onClick = { scope.launch { state.show() } }) { Text("Click to show sheet") }
    }
}
```



### ModalBottomSheet

https://developer.android.com/develop/ui/compose/components/bottom-sheets?hl=ja

Material3用のボトムシートのコンポーザブルです。
基本的にはModalBottomSheetLayoutと同じです。
ModalBottomSheetではボトムシートの状態を自分で管理するため、MutableStateで変数を作成しています。
こちらでは通常の画面をwrapする必要はなく、if文などで表示するかどうかを別要素として管理すれば良いので、書き方が分かりやすくなった気がします。
他の違いなどは[こちら](https://qiita.com/ntsk/items/5704a1da14a3ff9b5602)が参考になりました。

```ModalBottomSheetSample.kt
    val sheetState = rememberModalBottomSheetState()
    val scope = rememberCoroutineScope()
    var showBottomSheet by remember { mutableStateOf(false) }
    Scaffold(
        floatingActionButton = {
            ExtendedFloatingActionButton(
                text = { Text("Show bottom sheet") },
                icon = { Icon(Icons.Filled.Add, contentDescription = "") },
                onClick = {
                    showBottomSheet = true
                }
            )
        }
    ) { contentPadding ->
        // Screen content
        
        if (showBottomSheet) {
            ModalBottomSheet(
                onDismissRequest = {
                    showBottomSheet = false
                },
                sheetState = sheetState
            ) {
                // Sheet content
                Button(onClick = {
                    scope.launch { sheetState.hide() }.invokeOnCompletion {
                        if (!sheetState.isVisible) {
                            showBottomSheet = false
                        }
                    }
                }) {
                    Text("Hide bottom sheet")
                }
            }
        }
    }

```








### BottomSheetScaffold

https://developer.android.com/reference/kotlin/androidx/compose/material/package-summary#BottomSheetScaffold(kotlin.Function1,androidx.compose.ui.Modifier,androidx.compose.material.BottomSheetScaffoldState,kotlin.Function0,kotlin.Function1,kotlin.Function0,androidx.compose.material.FabPosition,kotlin.Boolean,androidx.compose.ui.graphics.Shape,androidx.compose.ui.unit.Dp,androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Color,androidx.compose.ui.unit.Dp,androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Color,kotlin.Function1)

何かのボタンをタップした時に一時的に表示するボトムシートでなく、常に表示しておきたい時に使うボトムシートです。
スクロールして一部開いておいたり、ほとんど隠した状態にできるもの。

```BottomSheetScaffold.kt
    val scope = rememberCoroutineScope()
    val scaffoldState = rememberBottomSheetScaffoldState()
    BottomSheetScaffold(
        sheetContent = {
            Box(
                Modifier
                    .fillMaxWidth()
                    .height(128.dp), contentAlignment = Alignment.Center
            ) {
                Text("Swipe up to expand sheet")
            }
            Column(
                Modifier
                    .fillMaxWidth()
                    .padding(64.dp),
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text("Sheet content")
                Spacer(Modifier.height(20.dp))
                Button(onClick = {}) {
                    Text("Click to collapse sheet")
                }
            }
        },
        scaffoldState = scaffoldState,
        topBar = {
            TopAppBar(title = { Text("Bottom sheet scaffold") })
        },
        sheetPeekHeight = 128.dp
    ) { innerPadding ->
        LazyColumn(contentPadding = innerPadding) {
            items(100) {
                Box(
                    Modifier
                        .fillMaxWidth()
                        .height(50.dp)
                        .background(color = androidx.compose.ui.graphics.Color.Gray)
                )
            }
        }
    }
```