Dialog
Hướng dẫn sử dụng các loại Dialog trong Compose Multiplatform.
AlertDialog cơ bản
@Composable
fun SimpleAlertDialog() {
var showDialog by remember { mutableStateOf(false) }
Button(onClick = { showDialog = true }) {
Text("Show Dialog")
}
if (showDialog) {
AlertDialog(
onDismissRequest = { showDialog = false },
title = { Text("Confirm Action") },
text = { Text("Are you sure you want to proceed?") },
confirmButton = {
TextButton(onClick = { showDialog = false }) {
Text("Confirm")
}
},
dismissButton = {
TextButton(onClick = { showDialog = false }) {
Text("Cancel")
}
}
)
}
}Custom Dialog
@Composable
fun CustomDialog(
show: Boolean,
onDismiss: () -> Unit,
onConfirm: () -> Unit
) {
if (show) {
Dialog(onDismissRequest = onDismiss) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
shape = RoundedCornerShape(16.dp)
) {
Column(
modifier = Modifier.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Icon(
Icons.Default.CheckCircle,
contentDescription = null,
modifier = Modifier.size(64.dp),
tint = Color.Green
)
Spacer(Modifier.height(16.dp))
Text(
"Success!",
style = MaterialTheme.typography.headlineSmall,
fontWeight = FontWeight.Bold
)
Spacer(Modifier.height(8.dp))
Text(
"Your action was completed successfully.",
textAlign = TextAlign.Center,
color = Color.Gray
)
Spacer(Modifier.height(24.dp))
Button(
onClick = onConfirm,
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(12.dp)
) {
Text("OK")
}
}
}
}
}
}Delete Confirmation Dialog
@Composable
fun DeleteConfirmationDialog(
show: Boolean,
itemName: String,
onConfirm: () -> Unit,
onDismiss: () -> Unit
) {
if (show) {
AlertDialog(
onDismissRequest = onDismiss,
icon = {
Icon(
Icons.Default.Delete,
contentDescription = null,
tint = MaterialTheme.colorScheme.error
)
},
title = {
Text("Delete $itemName?")
},
text = {
Text("This action cannot be undone. Are you sure you want to delete this item?")
},
confirmButton = {
Button(
onClick = {
onConfirm()
onDismiss()
},
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.error
)
) {
Text("Delete")
}
},
dismissButton = {
OutlinedButton(onClick = onDismiss) {
Text("Cancel")
}
}
)
}
}Input Dialog
@Composable
fun InputDialog(
show: Boolean,
title: String,
initialValue: String = "",
placeholder: String = "",
onConfirm: (String) -> Unit,
onDismiss: () -> Unit
) {
var text by remember { mutableStateOf(initialValue) }
if (show) {
AlertDialog(
onDismissRequest = onDismiss,
title = { Text(title) },
text = {
OutlinedTextField(
value = text,
onValueChange = { text = it },
placeholder = { Text(placeholder) },
modifier = Modifier.fillMaxWidth(),
singleLine = true
)
},
confirmButton = {
TextButton(
onClick = {
onConfirm(text)
onDismiss()
},
enabled = text.isNotBlank()
) {
Text("Save")
}
},
dismissButton = {
TextButton(onClick = onDismiss) {
Text("Cancel")
}
}
)
}
}
// Usage
@Composable
fun Example() {
var showDialog by remember { mutableStateOf(false) }
var name by remember { mutableStateOf("") }
Column {
Text("Name: $name")
Button(onClick = { showDialog = true }) {
Text("Change Name")
}
}
InputDialog(
show = showDialog,
title = "Enter your name",
initialValue = name,
placeholder = "Your name",
onConfirm = { name = it },
onDismiss = { showDialog = false }
)
}Date Picker Dialog
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DatePickerDialogExample() {
var showDatePicker by remember { mutableStateOf(false) }
var selectedDate by remember { mutableStateOf<Long?>(null) }
val datePickerState = rememberDatePickerState()
Column {
OutlinedButton(onClick = { showDatePicker = true }) {
Icon(Icons.Default.CalendarMonth, contentDescription = null)
Spacer(Modifier.width(8.dp))
Text(
selectedDate?.let { formatDate(it) } ?: "Select Date"
)
}
}
if (showDatePicker) {
DatePickerDialog(
onDismissRequest = { showDatePicker = false },
confirmButton = {
TextButton(
onClick = {
selectedDate = datePickerState.selectedDateMillis
showDatePicker = false
}
) {
Text("OK")
}
},
dismissButton = {
TextButton(onClick = { showDatePicker = false }) {
Text("Cancel")
}
}
) {
DatePicker(state = datePickerState)
}
}
}
private fun formatDate(timestamp: Long): String {
// Format timestamp to readable date
return "Selected date"
}Time Picker Dialog
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TimePickerDialogExample() {
var showTimePicker by remember { mutableStateOf(false) }
val timePickerState = rememberTimePickerState()
Column {
OutlinedButton(onClick = { showTimePicker = true }) {
Icon(Icons.Default.Schedule, contentDescription = null)
Spacer(Modifier.width(8.dp))
Text("${timePickerState.hour}:${timePickerState.minute.toString().padStart(2, '0')}")
}
}
if (showTimePicker) {
Dialog(onDismissRequest = { showTimePicker = false }) {
Card(shape = RoundedCornerShape(16.dp)) {
Column(
modifier = Modifier.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
"Select Time",
style = MaterialTheme.typography.titleMedium
)
Spacer(Modifier.height(16.dp))
TimePicker(state = timePickerState)
Spacer(Modifier.height(16.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End
) {
TextButton(onClick = { showTimePicker = false }) {
Text("Cancel")
}
TextButton(onClick = { showTimePicker = false }) {
Text("OK")
}
}
}
}
}
}
}Loading Dialog
@Composable
fun LoadingDialog(
show: Boolean,
message: String = "Loading..."
) {
if (show) {
Dialog(
onDismissRequest = { },
properties = DialogProperties(
dismissOnBackPress = false,
dismissOnClickOutside = false
)
) {
Card(
shape = RoundedCornerShape(16.dp)
) {
Row(
modifier = Modifier.padding(24.dp),
verticalAlignment = Alignment.CenterVertically
) {
CircularProgressIndicator()
Spacer(Modifier.width(16.dp))
Text(message)
}
}
}
}
}Selection Dialog
@Composable
fun SingleSelectionDialog(
show: Boolean,
title: String,
options: List<String>,
selectedOption: String?,
onSelect: (String) -> Unit,
onDismiss: () -> Unit
) {
if (show) {
AlertDialog(
onDismissRequest = onDismiss,
title = { Text(title) },
text = {
LazyColumn {
items(options) { option ->
Row(
modifier = Modifier
.fillMaxWidth()
.clickable {
onSelect(option)
onDismiss()
}
.padding(vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically
) {
RadioButton(
selected = option == selectedOption,
onClick = null
)
Spacer(Modifier.width(8.dp))
Text(option)
}
}
}
},
confirmButton = {
TextButton(onClick = onDismiss) {
Text("Cancel")
}
}
)
}
}📝 Tóm tắt
| Dialog Type | Mục đích |
|---|---|
AlertDialog | Thông báo, xác nhận |
Dialog | Custom layout |
DatePickerDialog | Chọn ngày |
TimePicker | Chọn giờ |
Best Practices
- Clear actions - Buttons rõ ràng
- Concise content - Không quá dài
- Dismissible - Có thể đóng được
- Loading cannot dismiss - Loading dialog không cho đóng
Tiếp theo
Học về Form và Validation.
Last updated on