Android Compose Dialog 定制

1,399 阅读4分钟

Compose中的Dialog

在Jetpack Compose中,Dialog 是用于在屏幕上展示弹出式窗口的组件。Compose 官方提供了两种常见的对话框类型,用于满足不同的需求。

  1. AlertDialog(常规型)

AlertDialog 是最常用的对话框,主要用于显示一些简单的信息和操作选项(如确认、取消)。它给我们提供了一些基本框架结构。我们只需要以参数的形式传递进去,即可完成简单需求。但填进去后组装的东西真的是我们想要的吗 ~~!?

基本用法

@Composable
fun AlertDialogSample(showDialog: Boolean, onDismiss: () -> Unit) {
    if (showDialog) {
        AlertDialog(
            onDismissRequest = onDismiss,
            title = {
                Text(text = "提示")
            },
            text = {
                Text("这是一个简单的提示对话框。")
            },
            confirmButton = {
                TextButton(onClick = onDismiss) {
                    Text("确认")
                }
            },
            dismissButton = {
                TextButton(onClick = onDismiss) {
                    Text("取消")
                }
            }
        )
    }
}

在这个示例中,通过 showDialog 控制对话框的显示,通过 onDismissRequest 来处理对话框的关闭事件。

  1. Custom Dialog (洒脱型)

为什么叫他洒脱型弹窗呢。它高度可定制,就是给我们定义了一个框框,里面需要显示什么东西,我们都可以自己填。好处就是太自由了干啥都行,坏处也很明显,用起来太麻烦。内部UI都需要自己一步一步搭建。我们可以使用下面代码来实现一个更加灵活的自定义弹窗。

基本用法

@Composable
fun CustomDialog(showDialog: Boolean, onDismiss: () -> Unit) {
    if (showDialog) {
        Dialog(onDismissRequest = onDismiss) {
            Surface(
                shape = MaterialTheme.shapes.medium,
                color = MaterialTheme.colorScheme.background
            ) {
                Column(
                    modifier = Modifier.padding(16.dp),
                    horizontalAlignment = Alignment.CenterHorizontally
                ) {
                    Text(text = "自定义对话框", style = MaterialTheme.typography.h6)
                    Spacer(modifier = Modifier.height(8.dp))
                    Text(text = "这里是自定义内容区域。")
                    Spacer(modifier = Modifier.height(16.dp))
                    Button(onClick = onDismiss) {
                        Text("关闭")
                    }
                }
            }
        }
    }
}

这里使用了 Dialog 组件和 Surface 容器来自定义对话框的内容和样式。

托福雅思App自定义的Dialog

由于项目中需要用到弹窗的地方很多,而且公共成分很大。每次都自定义弹窗各个地方的组件是非常繁琐的事,所以我们根据Compose的Dialog组件自定义通用Dialog。抽取公共特性,支持仅传递必要关键信息,即可快捷显示出相关弹窗。

  1. TwoActionDialogWithTitle(自定义通用型)

基本用法

@Composable
fun TwoActionDialogWithTitle(title:String,content:String,leftText:String,rightText:String,onLeftClick:()->Unit,onRightClick:()->Unit,onDismiss: () -> Unit={},cancelAble:Boolean=true) {
    Dialog(
        onDismissRequest = { onDismiss() },
        properties = DialogProperties(dismissOnBackPress = cancelAble, dismissOnClickOutside = cancelAble)
    ) {
        Surface(
            shape = RoundedCornerShape(8.dp),
            color = IeltsTheme.currentMode.bg_level2_color,
            modifier = Modifier
                .width(266.dp)
        ) {
            Column(
                modifier = Modifier.fillMaxWidth(),
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(start = 20.dp, end = 20.dp, top = 15.dp, bottom = 8.dp),
                    text = title,
                    fontSize = 16.sp,
                    fontWeight = FontWeight.Bold,
                    color = IeltsTheme.currentMode.text_primary_color,
                    textAlign = TextAlign.Center,
                )

                Text(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(start = 20.dp, end = 20.dp, bottom = 20.dp),
                    text = content,
                    fontSize = 14.sp,
                    color = IeltsTheme.currentMode.text_primary_color,
                    textAlign = TextAlign.Center,
                )

                Divider(
                    thickness = 1.dp,
                    color = IeltsTheme.currentMode.line_hard_color,
                    modifier = Modifier.fillMaxWidth()
                )
                Row (
                    modifier = Modifier.fillMaxWidth(),
                    verticalAlignment = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.SpaceEvenly
                    ){
                    Box (modifier = Modifier.clickable (
                        interactionSource = remember { MutableInteractionSource() },
                        indication=null){
                        onLeftClick()
                    }){
                        Text(
                            modifier = Modifier
                                .padding(vertical = 10.dp, horizontal = 30.dp),
                            text = leftText,
                            fontSize = 16.sp,
                            color = IeltsTheme.currentMode.text_secondary_color,
                            textAlign = TextAlign.Center,
                        )
                    }
                    Divider(
                        thickness = 44.dp,
                        color = IeltsTheme.currentMode.line_hard_color,
                        modifier = Modifier.width(1.dp)
                    )
                    Box (modifier = Modifier.clickable (
                        interactionSource = remember { MutableInteractionSource() },
                        indication=null){
                        onRightClick()
                    }){
                        Text(
                            modifier = Modifier
                                .padding(vertical = 10.dp, horizontal = 30.dp),
                            text = rightText,
                            fontSize = 16.sp,
                            color = IeltsTheme.currentMode.text_brand_color,
                            textAlign = TextAlign.Center,
                        )
                    }

                }

            }
        }
    }
}

上面代码向我们展示了自定义Compose中的Dialog的抽取出的公共参数,Dialog自定义配置,及使用等。下面我们介绍一下参数与显示界面功能对应关系

参数与功能对照表

参数名解释说明
title顶部居中显示的弹窗标题
contenttitle下面居中显示的弹窗说明文案
leftText左侧下面按钮的文案
rightText右侧下面按钮的文案
onLeftClick左侧下面按钮(leftText文案)点击时触发的事件回调(事件上浮到使用处)。
onRightClick右侧下面按钮(rightText文案)点击时触发的事件回调(事件上浮到使用处)。
onDismissDialog弹窗关闭时的回调(事件上浮到调用处,供外界处理相关逻辑)
cancelAble弹窗(在点击back返回按钮或者点击弹窗外部区域时)是否可以取消
  1. TwoActionDialogWithTitle(支持content显示为自定义组件)

基本用法

@Composable
fun TwoActionDialogWithTitle(title:String,content:@Composable ()->Unit,leftText:String,rightText:String,onLeftClick:()->Unit,onRightClick:()->Unit,onDismiss: () -> Unit={},cancelAble:Boolean=true) {
    Dialog(
        onDismissRequest = { onDismiss() },
        properties = DialogProperties(dismissOnBackPress = cancelAble, dismissOnClickOutside = cancelAble)
    ) {
        Surface(
            shape = RoundedCornerShape(8.dp),
            color = IeltsTheme.currentMode.bg_level2_color,
            modifier = Modifier
                .width(266.dp)
        ) {
            Column(
                modifier = Modifier.fillMaxWidth(),
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(start = 20.dp, end = 20.dp, top = 15.dp, bottom = 8.dp),
                    text = title,
                    fontSize = 16.sp,
                    fontWeight = FontWeight.Bold,
                    color = IeltsTheme.currentMode.text_primary_color,
                    textAlign = TextAlign.Center,
                )

                content()

                Divider(
                    thickness = 1.dp,
                    color = IeltsTheme.currentMode.line_hard_color,
                    modifier = Modifier.fillMaxWidth()
                )
                Row (
                    modifier = Modifier.fillMaxWidth(),
                    verticalAlignment = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.SpaceEvenly
                ){
                    Box (modifier = Modifier.clickable (
                        interactionSource = remember { MutableInteractionSource() },
                        indication=null){
                        onLeftClick()
                    }){
                        Text(
                            modifier = Modifier
                                .padding(vertical = 10.dp, horizontal = 30.dp),
                            text = leftText,
                            fontSize = 16.sp,
                            color = IeltsTheme.currentMode.text_secondary_color,
                            textAlign = TextAlign.Center,
                        )
                    }
                    Divider(
                        thickness = 44.dp,
                        color = IeltsTheme.currentMode.line_hard_color,
                        modifier = Modifier.width(1.dp)
                    )
                    Box (modifier = Modifier.clickable (
                        interactionSource = remember { MutableInteractionSource() },
                        indication=null){
                        onRightClick()
                    }){
                        Text(
                            modifier = Modifier
                                .padding(vertical = 10.dp, horizontal = 30.dp),
                            text = rightText,
                            fontSize = 16.sp,
                            color = IeltsTheme.currentMode.text_brand_color,
                            textAlign = TextAlign.Center,
                        )
                    }

                }

            }
        }
    }
}

上面代码与1中几乎一样,但是参数中content字段不是String类型的而是支持用户自定义的可组合函数类型。第二个函数通过重载的方式,向用户提供了自定义Content内容的能力,可以应付更加复杂的UI需求。

参数与功能对照表

参数名解释说明
title顶部居中显示的弹窗标题
content可组合函数,此处可完全自定义content的ui,解决更加复杂的设计需求
leftText左侧下面按钮的文案
rightText右侧下面按钮的文案
onLeftClick左侧下面按钮(leftText文案)点击时触发的事件回调(事件上浮到使用处)。
onRightClick右侧下面按钮(rightText文案)点击时触发的事件回调(事件上浮到使用处)。
onDismissDialog弹窗关闭时的回调(事件上浮到调用处,供外界处理相关逻辑)
cancelAble弹窗(在点击back返回按钮或者点击弹窗外部区域时)是否可以取消