JetPack Compose BottomSheet控件封装 - MultiBottomSheetLayout

2,695 阅读2分钟

Compose BottomSheet控件的封装,方便维护和调用,不用再去写重复代码了

1.简单,易懂,方便调用,支持Bundle数据传递到BottomSheet内部

MultiBottomSheetLayout(
        //bottomSheet顶部边距
        sheetModifier = Modifier.padding(top = 46.dp),
        sheetShape = 自己定义一个shape,
        sheetContent = { bundle ->
            //底部弹出来的BottomSheet,根据bundle解析数据渲染
            PopBottomScreen(arguments = bundle)
        }, mainContent = { openSheet ->
            //主界面内容,activityContentView
            MainContent(openSheet)
        })

2.我们先定义一个密封类MultiBottomSheet

sealed class MultiBottomSheet() {
    //支持传入Bundle,通过Bundle去解析数据,渲染新BottomSheet页面内容
    class Intent(val arguments:Bundle? = null):MultiBottomSheet()
}

密封类:自身抽象的,它不能直接实例化

kotlin不熟悉的可以去学习以下kotlin,本篇文章仅提供一个封装控件的整个流程讲解

3.Compose中要用BottomSheet,必须要创建一个BottomSheetScaffold脚手架

val bottomSheetScaffoldState = rememberBottomSheetScaffoldState(.....)
BottomSheetScaffold(
    sheetContent = {
        //想在底部弹出来显示的内容
    },
    scaffoldState = bottomSheetScaffoldState) {
        //显示在屏幕中的内容contentView
    }
)
//显示和关闭需要在协程中执行哦
//显示的时候,调用:bottomSheetScaffoldState.bottomSheetState.expand()
//关闭的时候,调用:bottomSheetScaffoldState.bottomSheetState.collapse()

4.开始封装MultiBottomSheetLayout

4.1 函数提取
@SuppressLint("ModifierParameter")
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun MultiBottomSheetLayout(
    sheetModifier: Modifier = Modifier,
    sheetElevation: Dp = 0.dp,
    sheetShape: Shape = MaterialTheme.shapes.large,
    mainContent: @Composable (sheetScreen: (MultiBottomSheet.Intent) -> Unit) -> Unit,
    sheetContent: @Composable (arguments: Bundle?) -> Unit,
    topLeftIcon: (@Composable (onClosePressed: () -> Unit) -> Unit)? = null,
    topCenterIcon: (@Composable (onClosePressed: () -> Unit) -> Unit)? = null,
    topRightIcon: (@Composable (onClosePressed: () -> Unit) -> Unit)? = null
){.....} 
4.2 记录状态,处理开关动作
    val scope = rememberCoroutineScope()
    val scaffoldState = rememberBottomSheetScaffoldState()
    //记录BottomSheet
    var currentBottomSheet: MultiBottomSheet.Intent? by remember{
        mutableStateOf(null)
    }
    //关闭的时候需要置空
    if(scaffoldState.bottomSheetState.isCollapsed){
        currentBottomSheet = null
    }
    //执行关闭BottomSheet
    val closeSheet: () -> Unit = {
        scope.launch {
            scaffoldState.bottomSheetState.collapse()
        }
    }
    //展开BottomSheet
    val openSheet: (MultiBottomSheet.Intent) -> Unit = {
        scope.launch {
            currentBottomSheet = it
            scaffoldState.bottomSheetState.expand()
        }
    }
4.3 状态和数据传入BottomSheetScaffold
BottomSheetScaffold(sheetPeekHeight = 0.dp, scaffoldState = scaffoldState,
        sheetElevation = sheetElevation,
        sheetShape = sheetShape,
        // 来设置BottomSheet弹出来的视图【距离】『屏幕顶部的距离』
        modifier = sheetModifier,
        sheetContent = {
            //显示弹出来的视图....
        }) { paddingValues ->
        Box(Modifier.padding(paddingValues)){
            //activityContentView
            mainContent(openSheet)
        }
    }

5.BottomSheetLayout支持外部传入topLeft,topCenter,topRight 顶部IconButton

这里我们需要把4.3里面的sheetContent = {....} 再提取一下,提炼出一个BottomSheetWithTopClose方法

@Composable
private fun BottomSheetWithTopClose(.....){
 Box(modifier.fillMaxWidth()) {
    content()
    if(topLeftIcon != null){
       IconButton(){
         topLeftIcon()
       }
    }
    //.......
 }
}

6.如果看了上面,👇👇不会封装的可以看一下我们封装好的代码:

MultiBottomSheetLayout.kt

里面有测试代码,有需要的,可以参考一下