Skip to Content

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 TypeMục đích
AlertDialogThông báo, xác nhận
DialogCustom layout
DatePickerDialogChọn ngày
TimePickerChọn giờ

Best Practices

  1. Clear actions - Buttons rõ ràng
  2. Concise content - Không quá dài
  3. Dismissible - Có thể đóng được
  4. Loading cannot dismiss - Loading dialog không cho đóng

Tiếp theo

Học về Form và Validation.

Last updated on