CMP for OpenHarmony:AlertDialog 对话框的“语义边界”实现——提示/确认/不可取消/pending 写回四种模式一次讲清(项目实战代码)
CMP for OpenHarmony:AlertDialog 对话框的“语义边界”实现——提示/确认/不可取消/pending 写回四种模式一次讲清(项目实战代码)
代码地址:通过网盘分享的文件:cmp_openharmony.zip
链接: https://pan.baidu.com/s/15rN1LvJ0KENMkYZfLq_R1Q?pwd=nhqe 提取码: nhqe
1. 代码位置:示例页在哪
本文所有 Kotlin 代码均来自下面文件(复制路径即可定位):
composeApp/src/commonMain/kotlin/com/tencent/compose/sample/dialog/DialogDemoPage.kt
2. 先把“弹窗类型”拆成 4 个可组合状态
示例页用 4 个 Boolean 控制不同对话框的显示(节选,保持项目原样):
var showInfo by remember { mutableStateOf(false) }
var showConfirm by remember { mutableStateOf(false) }
var showNonCancelable by remember { mutableStateOf(false) }
var showPending by remember { mutableStateOf(false) }
说明:
- Demo 同时演示多种对话框,因此用多个开关分别控制。
- 工程中如果只会出现“同一时刻最多一个弹窗”,也可以把它们合并成一个枚举状态,但本示例用多开关更直观。
3. 给弹窗一个“可观测输出”:lastResult 用于记录触发路径
示例页定义了 lastResult 作为结果记录(节选,保持项目原样):
var lastResult by remember { mutableStateOf("未触发") }
说明:
- Demo 页面里它负责把“关闭/确认/取消/拦截 dismiss”等行为可视化。
- 工程里你可以把
lastResult替换为日志、埋点或状态栏提示;关键是让对话框行为可追踪。
4. 提示型 AlertDialog:单按钮关闭,dismiss 与 confirm 都要显式处理
提示型对话框通常用于“告知”,它只有一个确认按钮,但仍然要处理两条关闭路径:
- 点击空白区域/返回:触发
onDismissRequest - 点击确认按钮:触发
confirmButton
示例实现(节选,保持项目原样):
if (showInfo) {
AlertDialog(
onDismissRequest = {
showInfo = false
lastResult = "提示型:关闭"
},
title = { Text(text = "提示") },
text = {
Text(
text = "这是一个最基础的提示型对话框:通常只提供一个确认按钮,用于告知用户信息。",
fontSize = 13.sp,
color = Color(0xFF333333)
)
},
confirmButton = {
Button(
onClick = {
showInfo = false
lastResult = "提示型:确认"
}
) {
Text(text = "知道了", color = Color.White)
}
}
)
}
说明:
- 这里的关键不是 UI 文案,而是两条关闭路径都要落到同一套状态变更:
- 都会把
showInfo = false,确保弹窗从树上移除。
- 都会把
onDismissRequest不应该留空,否则你会遇到“用户点击空白区域没反应”的不一致体验。
5. 确认/取消 AlertDialog:确认有副作用,取消必须保证“不写入”
确认/取消对话框的核心语义是:
- 确认:执行副作用(写入主状态、调用接口、提交配置等)
- 取消/关闭:不执行副作用
示例实现(节选,保持项目原样):
if (showConfirm) {
AlertDialog(
onDismissRequest = {
showConfirm = false
lastResult = "确认/取消:关闭"
},
title = { Text(text = "确认操作") },
text = {
Text(
text = "确认后会把 count + 10,并且会把 switch 置为 ON;取消则不修改主状态。",
fontSize = 13.sp,
color = Color(0xFF333333)
)
},
confirmButton = {
Button(
onClick = {
count += 10
switchValue = true
showConfirm = false
lastResult = "确认/取消:已确认(count=$count, switch=ON)"
}
) {
Text(text = "确认", color = Color.White)
}
},
dismissButton = {
Button(
onClick = {
showConfirm = false
lastResult = "确认/取消:取消"
},
colors = ButtonDefaults.buttonColors(backgroundColor = Color(0xFFE0E0E0))
) {
Text(text = "取消", color = Color(0xFF333333))
}
}
)
}
说明:
- 副作用只放在 confirmButton:本例确认时写入
count/switchValue。 onDismissRequest与dismissButton都不写入主状态,只负责关闭弹窗并记录来源。- 这能避免一个常见 bug:用户只是误触关闭,却触发了状态写入。
6. 不可取消 AlertDialog:用 onDismissRequest 显式拦截
有些业务场景不允许“点空白区域就关闭”(例如必须确认协议、必须等待某个关键步骤)。这种情况下要把 onDismissRequest 变成一个“拦截器”。
示例实现(节选,保持项目原样):
if (showNonCancelable) {
AlertDialog(
onDismissRequest = {
lastResult = "不可取消:已拦截 dismiss"
},
title = { Text(text = "不可取消") },
text = {
Text(
text = "这个对话框不允许点击空白区域关闭,你必须点击下方按钮主动关闭。",
fontSize = 13.sp,
color = Color(0xFF333333)
)
},
confirmButton = {
Button(
onClick = {
showNonCancelable = false
lastResult = "不可取消:关闭"
}
) { Text(text = "关闭", color = Color.White) }
}
)
}
说明:
- 这里
onDismissRequest不把showNonCancelable置为 false,等价于“拦截”。 - 真正的关闭只能从
confirmButton走,这样对话框的关闭路径是可控的。
7. pending 写回:把对话框当作“编辑缓冲区”,确认时再落主状态
很多对话框并不是单纯确认/取消,而是“在弹窗里编辑多个字段”。如果你在弹窗里每点一下就立刻写回主状态,会出现两类问题:
- 用户还没点确认,主界面状态已经变了(语义不一致)
- 用户点取消时很难恢复(需要回滚逻辑)
示例页采用 pendingSwitch/pendingCount 作为缓冲区,并在打开弹窗时初始化(节选,保持项目原样):
var pendingSwitch by remember { mutableStateOf(switchValue) }
var pendingCount by remember { mutableIntStateOf(count) }
LaunchedEffect(showPending) {
if (showPending) {
pendingSwitch = switchValue
pendingCount = count
}
}
说明:
pending*是弹窗内部的临时值。LaunchedEffect(showPending)确保每次打开弹窗都从主状态同步一份初始值,避免上次编辑残留。
7.1 在弹窗内部修改 pending 值
示例里通过 Switch 和两个可点击区域修改 pendingCount(节选,保持项目原样):
Switch(checked = pendingSwitch, onCheckedChange = { pendingSwitch = it })
pendingCount -= 1
pendingCount += 1
说明:
- 这里的重点是:所有修改都只作用于
pending*,不会影响页面主状态。 - 这让“取消”变得廉价:直接关闭弹窗即可,不需要做回滚。
7.2 点击“写回”才更新主状态
写回按钮实现(节选,保持项目原样):
Button(
onClick = {
switchValue = pendingSwitch
count = pendingCount
showPending = false
lastResult = "pending:已写回(switch=${if (switchValue) "ON" else "OFF"}, count=$count)"
}
) {
Text(text = "写回", color = Color.White)
}
说明:
- 这就是对话框的“提交边界”:只有在确认按钮点击时才写入主状态。
- 这类模式非常适合做“设置项编辑”“批量参数调整”等场景。
8. 自检清单:AlertDialog 工程里最容易踩的坑
- 关闭路径不一致:
confirmButton关了弹窗,但onDismissRequest没关,会导致行为割裂。 - 取消也产生副作用:确认/取消对话框里,副作用必须只在 confirm 分支。
- 不可取消实现错误:想不可取消却还在
onDismissRequest里show=false,等于没有拦截。 - 编辑型弹窗缺少 pending 缓冲区:导致“没点确认主状态就变了”,取消要做回滚。

欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net openharmony社区链接
更多推荐



所有评论(0)