AlertDialog
2026/1/31大约 4 分钟
AlertDialog
概述
AlertDialog 是 Compose 中用于显示模态对话框(modal dialog)的标准组件,常用于提示用户确认、展示重要信息或请求简单输入。Compose 有两个常用实现:androidx.compose.material 的 AlertDialog(Material 2 风格)和 androidx.compose.material3 的 AlertDialog(Material 3 风格),API 大致相似。
常用 API 与参数
onDismissRequest: () -> Unit:必须提供,用户触摸对话框外部或按返回键时回调。应在此回调中关闭对话框。title: (@Composable () -> Unit)?:可选标题 Composable,通常传入Text。text: (@Composable () -> Unit)?:可选正文内容 Composable,适合展示描述或细节文本。confirmButton: @Composable () -> Unit:确认按钮 slot(例如Button)。dismissButton: @Composable () -> Unit:取消/辅助按钮 slot(例如TextButton)。properties: DialogProperties:控制对话框属性(是否可聚焦、是否可点击外部关闭、是否使用安全区域等)。shape,backgroundColor,contentColor,tonalElevation(Material3)等:用于定制外观。
额外对比:
AlertDialog是基于Dialog的高阶封装;当你需要完全自定义的布局时可以直接使用Dialog或Popup。
使用模式与注意事项
- 状态提升(State hoisting):对话框的显示状态应由外部持有(例如
var show by remember { mutableStateOf(false) }),并通过onDismissRequest以及按钮回调修改。 - 不可阻塞 UI:避免在
onDismissRequest或按钮回调中做长时阻塞操作,使用协程或 ViewModel 处理耗时任务。 - 无障碍(Accessibility):为
title或text使用可读的文本,必要时提供内容描述。
代码示例
1. 基本的确认对话框
@Composable
fun SimpleConfirmDialog(showDialog: Boolean, onDismiss: () -> Unit, onConfirm: () -> Unit) {
if (!showDialog) return
AlertDialog(
onDismissRequest = onDismiss,
title = { Text("删除确认") },
text = { Text("确定要删除这条记录吗?该操作无法撤销。") },
confirmButton = {
TextButton(onClick = {
onConfirm()
onDismiss()
}) { Text("确定") }
},
dismissButton = {
TextButton(onClick = onDismiss) { Text("取消") }
}
)
}调用示例:
@Composable
fun ConfirmDialogDemo() {
var show by remember { mutableStateOf(false) }
Column {
Button(onClick = { show = true }) { Text("删除项") }
SimpleConfirmDialog(
showDialog = show,
onDismiss = { show = false },
onConfirm = { /* 执行删除逻辑 */ }
)
}
}2. 带输入(TextField)的对话框
@Composable
fun InputDialog(
showDialog: Boolean,
initialText: String = "",
onDismiss: () -> Unit,
onConfirm: (String) -> Unit
) {
if (!showDialog) return
var text by remember { mutableStateOf(initialText) }
AlertDialog(
onDismissRequest = onDismiss,
title = { Text("输入名称") },
text = {
Column {
Text("请输入项目名称:")
Spacer(modifier = Modifier.height(8.dp))
TextField(value = text, onValueChange = { text = it })
}
},
confirmButton = {
TextButton(onClick = {
onConfirm(text)
onDismiss()
}) { Text("保存") }
},
dismissButton = { TextButton(onClick = onDismiss) { Text("取消") } }
)
}3. 选择列表(单选)对话框
@Composable
fun SingleChoiceDialog(
showDialog: Boolean,
options: List<String>,
selectedIndex: Int,
onDismiss: () -> Unit,
onSelect: (Int) -> Unit
) {
if (!showDialog) return
var choice by remember { mutableStateOf(selectedIndex) }
AlertDialog(
onDismissRequest = onDismiss,
title = { Text("选择一项") },
text = {
Column {
options.forEachIndexed { index, label ->
Row(modifier = Modifier
.fillMaxWidth()
.selectable(
selected = (choice == index),
onClick = { choice = index }
)
.padding(8.dp)) {
RadioButton(selected = (choice == index), onClick = { choice = index })
Spacer(Modifier.width(8.dp))
Text(label)
}
}
}
},
confirmButton = {
TextButton(onClick = {
onSelect(choice)
onDismiss()
}) { Text("确定") }
},
dismissButton = { TextButton(onClick = onDismiss) { Text("取消") } }
)
}4. 完全自定义内容(带图片或任意 Composable)
@Composable
fun CustomContentDialog(showDialog: Boolean, onDismiss: () -> Unit) {
if (!showDialog) return
AlertDialog(
onDismissRequest = onDismiss,
title = { Text("自定义对话框") },
text = {
Column {
Image(
painter = painterResource(id = R.drawable.ic_sample),
contentDescription = null,
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.height(8.dp))
Text("这是一段自定义内容,可以包含任意 Composable。")
}
},
confirmButton = { TextButton(onClick = onDismiss) { Text("好的") } }
)
}进阶:使用 Dialog 自定义交互
当需要超过 AlertDialog 能力范围的自定义行为(例如复杂动画、拖拽、或非矩形背景)时,可以直接使用 Dialog:
@Composable
fun FullCustomDialog(show: Boolean, onDismiss: () -> Unit) {
if (!show) return
Dialog(onDismissRequest = onDismiss) {
Surface(shape = RoundedCornerShape(8.dp)) {
Column(modifier = Modifier.padding(16.dp)) {
Text("完全自定义对话框")
// 自定义内容
}
}
}
}小结与最佳实践
- 使用
AlertDialog满足大多数确认/提示场景;复杂 UI 使用Dialog。 - 状态提升:对话框的显示控制应在调用方持有状态。
- 在对话框按钮回调中避免直接执行耗时任务;应将工作交给 ViewModel/协程。
参考
androidx.compose.material.AlertDialog文档androidx.compose.material3.AlertDialog(Material 3)
代码
package com.example.note.jetpack.examples
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.selection.selectable
import androidx.compose.material.AlertDialog
import androidx.compose.material.Button
import androidx.compose.material.Image
import androidx.compose.material.RadioButton
import androidx.compose.material.Scaffold
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material.TextField
import androidx.compose.material.rememberScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.note.R
@Composable
fun SimpleConfirmDialog(showDialog: Boolean, onDismiss: () -> Unit, onConfirm: () -> Unit) {
if (!showDialog) return
AlertDialog(
onDismissRequest = onDismiss,
title = { Text("删除确认") },
text = { Text("确定要删除这条记录吗?该操作无法撤销。") },
confirmButton = {
TextButton(onClick = {
onConfirm()
onDismiss()
}) { Text("确定") }
},
dismissButton = {
TextButton(onClick = onDismiss) { Text("取消") }
}
)
}
@Preview(showBackground = true)
@Composable
fun PreviewSimpleConfirmDialog() {
var show by remember { mutableStateOf(true) }
SimpleConfirmDialog(showDialog = show, onDismiss = { show = false }, onConfirm = {})
}
@Composable
fun InputDialog(showDialog: Boolean, initialText: String = "", onDismiss: () -> Unit, onConfirm: (String) -> Unit) {
if (!showDialog) return
var text by remember { mutableStateOf(initialText) }
AlertDialog(
onDismissRequest = onDismiss,
title = { Text("输入名称") },
text = {
Column {
Text("请输入项目名称:")
Spacer(modifier = Modifier.height(8.dp))
TextField(value = text, onValueChange = { text = it })
}
},
confirmButton = {
TextButton(onClick = {
onConfirm(text)
onDismiss()
}) { Text("保存") }
},
dismissButton = { TextButton(onClick = onDismiss) { Text("取消") } }
)
}
@Preview(showBackground = true)
@Composable
fun PreviewInputDialog() {
var show by remember { mutableStateOf(true) }
InputDialog(showDialog = show, onDismiss = { show = false }, onConfirm = {})
}
@Composable
fun SingleChoiceDialog(showDialog: Boolean, options: List<String>, selectedIndex: Int, onDismiss: () -> Unit, onSelect: (Int) -> Unit) {
if (!showDialog) return
var choice by remember { mutableStateOf(selectedIndex) }
AlertDialog(
onDismissRequest = onDismiss,
title = { Text("选择一项") },
text = {
Column {
options.forEachIndexed { index, label ->
androidx.compose.foundation.layout.Row(modifier = Modifier
.fillMaxWidth()
.selectable(
selected = (choice == index),
onClick = { choice = index }
)
.padding(8.dp)) {
RadioButton(selected = (choice == index), onClick = { choice = index })
Spacer(Modifier.height(4.dp))
Text(label)
}
}
}
},
confirmButton = {
TextButton(onClick = {
onSelect(choice)
onDismiss()
}) { Text("确定") }
},
dismissButton = { TextButton(onClick = onDismiss) { Text("取消") } }
)
}
@Preview(showBackground = true)
@Composable
fun PreviewSingleChoiceDialog() {
var show by remember { mutableStateOf(true) }
SingleChoiceDialog(showDialog = show, options = listOf("A","B","C"), selectedIndex = 0, onDismiss = { show = false }, onSelect = {})
}
@Composable
fun CustomContentDialog(showDialog: Boolean, onDismiss: () -> Unit) {
if (!showDialog) return
AlertDialog(
onDismissRequest = onDismiss,
title = { Text("自定义对话框") },
text = {
Column {
Image(painter = painterResource(id = R.drawable.ic_sample), contentDescription = null, modifier = Modifier.fillMaxWidth())
Spacer(modifier = Modifier.height(8.dp))
Text("这是一段自定义内容,可以包含任意 Composable。")
}
},
confirmButton = { TextButton(onClick = onDismiss) { Text("好的") } }
)
}
@Preview(showBackground = true)
@Composable
fun PreviewCustomContentDialog() {
var show by remember { mutableStateOf(true) }
CustomContentDialog(showDialog = show, onDismiss = { show = false })
}