Jetpack Compose 中一个 ModalBottomSheetLayout 的多个 BottomSheets

Yan*_*ick 6 android android-jetpack-compose

我想实现一个可以显示两个不同底部工作表的屏幕。由于ModalBottomSheetLayout只有一个片槽我决定改变sheetContentModalBottomSheetLayout动态使用selected状态时我要显示或者在两个片材(的全码)。

val sheetState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)

val (selected, setSelected) = remember(calculation = { mutableStateOf(0) })

ModalBottomSheetLayout(sheetState = sheetState, sheetContent = {
    when (selected) {
       0 -> Layout1()
       1 -> Layout2()
    }
}) {
   Content(sheetState = sheetState, setSelected = setSelected)
}
Run Code Online (Sandbox Code Playgroud)

这适用于非常相似的工作表,但是一旦您向两个工作表布局中的任何一个添加更多复杂性,第一次按下按钮时工作表将不会显示,它只会在您按下按钮两次后显示可以在这里看到:

2

在这里你可以找到一个可重现的例子

jns*_*jns 7

我有一个类似的用例,我需要显示 2-3 个堆叠的底页。我最终复制了 Compose BottomSheet 的大部分内容并添加了所需的行为:

enum class BottomSheetValue { SHOWING, HIDDEN }

@Composable
fun BottomSheet(
        parentHeight: Int,
        topOffset: Dp = 0.dp,
        fillMaxHeight: Boolean = false,
        sheetState: SwipeableState<BottomSheetValue>,
        shape: Shape = bottomSheetShape,
        backgroundColor: Color = MaterialTheme.colors.background,
        contentColor: Color = contentColorFor(backgroundColor),
        elevation: Dp = 0.dp,
        content: @Composable () -> Unit
) {
    val topOffsetPx = with(LocalDensity.current) { topOffset.roundToPx() }
    var bottomSheetHeight by remember { mutableStateOf(parentHeight.toFloat())}

    val scrollConnection = sheetState.PreUpPostDownNestedScrollConnection

    BottomSheetLayout(
        maxHeight = parentHeight - topOffsetPx,
        fillMaxHeight = fillMaxHeight
    ) {
        val swipeable = Modifier.swipeable(
            state = sheetState,
            anchors = mapOf(
                parentHeight.toFloat() to BottomSheetValue.HIDDEN,
                parentHeight - bottomSheetHeight to BottomSheetValue.SHOWING
            ),
            orientation = Orientation.Vertical,
            resistance = null
        )

        Surface(
            shape = shape,
            color = backgroundColor,
            contentColor = contentColor,
            elevation = elevation,
            modifier = Modifier
                .nestedScroll(scrollConnection)
                .offset { IntOffset(0, sheetState.offset.value.roundToInt()) }
                .then(swipeable)
                .onGloballyPositioned {
                    bottomSheetHeight = it.size.height.toFloat()
                },
        ) {
            content()
        }
    }
}


@Composable
private fun BottomSheetLayout(
        maxHeight: Int,
        fillMaxHeight: Boolean,
        content: @Composable () -> Unit
) {
    Layout(content = content) { measurables, constraints ->
        val sheetConstraints =
            if (fillMaxHeight) {
                constraints.copy(minHeight = maxHeight, maxHeight = maxHeight)
            } else {
                constraints.copy(maxHeight = maxHeight)
            }

        val placeable = measurables.first().measure(sheetConstraints)

        layout(placeable.width, placeable.height) {
            placeable.placeRelative(0, 0)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

TopOffset 例如允许将 BottomSheet 放置在 AppBar 下方:

BoxWithConstraints {
 BottomSheet(
                parentHeight = constraints.maxHeight,
                topOffset = with(LocalDensity.current) {56.toDp()}
                fillMaxHeight = true,
                sheetState = yourSheetState,
            ) {
                content()
            }
}
Run Code Online (Sandbox Code Playgroud)


Tim*_*lin 6

我是这样实现的。它看起来很简单,但我仍然不知道如何直接将参数传递给“mutableStateOf()”,我必须创建一个变量“content”

fun Screen() {
    val bottomSheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)
    val scope = rememberCoroutineScope()
    val content: @Composable (() -> Unit) = { Text("NULL") }
    var customSheetContent by remember { mutableStateOf(content) }
    ModalBottomSheetLayout(
        sheetState = bottomSheetState,
        sheetContent = {
            customSheetContent()
        }
    ) {
        Column {
        Button(
            onClick = {
                customSheetContent = { SomeComposable1() }
                scope.launch { bottomSheetState.show() }
        }) {
         Text("First Button")
        }

        Button(
            onClick = {
                customSheetContent = { SomeComposable2() }
                scope.launch { bottomSheetState.show() }
        }) {
         Text("Second Button")
        }
    }
    }
Run Code Online (Sandbox Code Playgroud)