android Jetpack合成-更改半展开状态的ModalBottomSheetLayout高度

1cosmwyk  于 2023-03-27  发布在  Android
关注(0)|答案(2)|浏览(355)

我为我的ModalBottomSheetLayout使用两个状态:HalfExpandedExpanded

val sheetState = rememberModalBottomSheetState(
    initialValue = if (isFullScreen) {
        ModalBottomSheetValue.Expanded
    } else {
        ModalBottomSheetValue.HalfExpanded
    }
)

ModalBottomSheetLayout(
    sheetState = sheetState,
    sheetContent = {
        Spacer(modifier = Modifier.height(1.dp))
        content()
    },
    modifier = modifier,
    content = {}
)

我的问题是HalfExpanded状态正好占据了屏幕的一半,但我需要70%的屏幕。有没有办法在HalfExpanded状态下强制ModalBottomSheetLayout显示70%的屏幕?

ryevplcw

ryevplcw1#

将initialValue设置为ModalBottomSheetValue。
保留一个sizeRatio变量,该变量将被分配给修改器以在70%和全屏(100%)之间进行交换

var sizeRatio by remember{mutableStateOf(0.7f)}

将sheetContent Package 在Column中,并设置Modifier.fillMaxHeight(sizeRatio)

ModalBottomSheetLayout(
sheetState = sheetState,
sheetContent = {
    Column(modifier = Modifier.fillMaxHeight(sizeRatio)){
        Spacer(modifier = Modifier.height(1.dp))
        content()
    }
},
modifier = modifier,
content = {})

如果你想显示抽屉使用在70%的覆盖率

sizeRatio = 0.7f
sheetState.animateTo(ModalBottomSheetValue.Expanded)

如果您希望抽屉在全屏重置回1f

sizeRatio = 1f
sheetState.animateTo(ModalBottomSheetValue.Expanded)

根据需求分配sizeRatio

sizeRatio = if(isFullScreen){ 1f } else { 0.7f }
                       
sheetState.animateTo(ModalBottomSheetValue.Expanded)

在ModalSheetLayout的修饰符中,可以使用此方法检测从here获得的向上滑动

更新整个刷卡手势

ModalBottomSheetLayout(
sheetState = sheetState,
    sheetContent = {
        Column(
            verticalArrangement = Arrangement.Center,
            modifier = Modifier.fillMaxHeight(sizeRatio).pointerInput(Unit)
            {
                detectDragGestures { change, dragAmount ->
                    change.consume()
                    val (x, y) = dragAmount
                    when {
                        y > 0 -> {
                            coroutineScope.launch {
                                sheetState.hide()
                            }
                        }

                        y < 0 -> {
                            coroutineScope.launch {
                                if (sheetState.currentValue == ModalBottomSheetValue.Expanded) {
                                    sizeRatio = 1f
                                }
                                sheetState.animateTo(ModalBottomSheetValue.Expanded)
                            }
                        }
                    }
                    offsetX += dragAmount.x
                    offsetY += dragAmount.y
                }
            },
        ) {
            Column(
                modifier = Modifier.fillMaxSize(),
            ) {
                Spacer(modifier = Modifier.height(1.dp))
                content()
            }
        }
    },
content = {},
modifier = Modifier.pointerInput(Unit)
    {
        detectDragGestures { change, dragAmount ->
            change.consume()
            val (x, y) = dragAmount
            when {
                y > 0 -> {
                    coroutineScope.launch {
                        sheetState.hide()
                    }
                }

                y < 0 -> {
                    coroutineScope.launch {
                        if (sheetState.currentValue != ModalBottomSheetValue.Expanded) {
                            sizeRatio = 0.7f
                        }
                        sheetState.animateTo(ModalBottomSheetValue.Expanded)
                    }
                }
            }
            offsetX += dragAmount.x
            offsetY += dragAmount.y
        }
    },
)

sheetContent中有两个嵌套Columns的原因是,只有在拖动内部内容时才会调用detectDragGestures
结果为

hiz5n14c

hiz5n14c2#

我最终想到的解决方案是使用Modifier.swipeable来处理ModalBottomSheetLayout内容。

@Suppress("ModifierInspectorInfo")
@OptIn(ExperimentalMaterialApi::class)
private fun Modifier.bottomSheetSwipeable(
    sheetState: ModalBottomSheetState,
    fullHeight: Float,
    sheetHeightState: State<Float?>,
    screenRatio: Float = 0.7f
): Modifier {
    val sheetHeight = sheetHeightState.value
    val modifier = if (sheetHeight != null) {
        val anchors = if (sheetHeight < fullHeight / 2) {
            mapOf(
                fullHeight to ModalBottomSheetValue.Hidden,
                fullHeight - sheetHeight to ModalBottomSheetValue.Expanded
            )
        } else {
            mapOf(
                fullHeight to ModalBottomSheetValue.Hidden,
                fullHeight - fullHeight * screenRatio to ModalBottomSheetValue.HalfExpanded,
                max(0f, fullHeight - sheetHeight) to ModalBottomSheetValue.Expanded
            )
        }
        Modifier.swipeable(
            state = sheetState,
            anchors = anchors,
            orientation = Orientation.Vertical,
            enabled = sheetState.currentValue != ModalBottomSheetValue.Hidden,
            resistance = null
        )
    } else {
        Modifier
    }

    return this.then(modifier)
}

用法:

sheetContent = {
            BottomSheetContent(
                modifier = modifier
                    .bottomSheetSwipeable(
                        sheetState = sheetState,
                        fullHeight = fullHeight,
                        sheetHeightState = sheetHeightState,
                        screenRatio = screenRatio
                    )
                    .onGloballyPositioned {
                        sheetHeightState.value = it.size.height.toFloat()
                    }
            )
        },

你还需要定义这些变量:

val configuration = LocalConfiguration.current
val fullHeight = with(LocalDensity.current) { configuration.screenHeightDp.dp.toPx() }
val sheetHeightState = remember { mutableStateOf<Float?>(null) }

相关问题