Dialog
Hướng dẫn sử dụng các loại Dialog trong Compose Multiplatform.
AlertDialog cơ bản
Phần tiêu đề “AlertDialog cơ bản”@Composablefun 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
Phần tiêu đề “Custom Dialog”@Composablefun 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
Phần tiêu đề “Delete Confirmation Dialog”@Composablefun 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
Phần tiêu đề “Input Dialog”@Composablefun 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@Composablefun 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
Phần tiêu đề “Date Picker Dialog”@OptIn(ExperimentalMaterial3Api::class)@Composablefun 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
Phần tiêu đề “Time Picker Dialog”@OptIn(ExperimentalMaterial3Api::class)@Composablefun 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
Phần tiêu đề “Loading Dialog”@Composablefun 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
Phần tiêu đề “Selection Dialog”@Composablefun 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
Phần tiêu đề “📝 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
Phần tiêu đề “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
Phần tiêu đề “Tiếp theo”Học về Form và Validation.