Bộ chọn ngày cho phép người dùng chọn một ngày, một phạm vi ngày hoặc cả hai. Các thành phần này sử dụng hộp thoại lịch hoặc phương thức nhập văn bản để cho phép người dùng chọn ngày.
Loại
Có ba loại bộ chọn ngày:
- Đã gắn: Xuất hiện cùng dòng trong bố cục. Phương thức này phù hợp với các bố cục nhỏ gọn, nơi hộp thoại chuyên dụng có thể gây khó chịu.
- Modal: Xuất hiện dưới dạng một hộp thoại phủ lên nội dung của ứng dụng. Điều này giúp bạn tập trung rõ ràng vào việc chọn ngày.
- Phương thức nhập mô-đun: Kết hợp một trường văn bản với bộ chọn ngày theo phương thức.
Bạn có thể triển khai các bộ chọn ngày này trong ứng dụng bằng cách sử dụng các thành phần kết hợp sau:
DatePicker
: Thành phần kết hợp chung cho bộ chọn ngày. Vùng chứa bạn sử dụng sẽ xác định xem vùng chứa đó là mô hình hay được kết nối.DatePickerDialog
: Vùng chứa cho cả ngày nhập phương thức và phương thức bộ chọn.DateRangePicker
: Đối với bất kỳ bộ chọn ngày nào mà người dùng có thể chọn ngày bắt đầu và ngày kết thúc.
Trạng thái
Tham số chính mà các thành phần kết hợp bộ chọn ngày khác nhau có chung là state
. Tham số này lấy đối tượng DatePickerState
hoặc DateRangePickerState
. Thuộc tính của họ thu thập thông tin về
lựa chọn của người dùng bằng cách sử dụng bộ chọn ngày, chẳng hạn như ngày hiện đã chọn.
Để biết thêm thông tin về cách sử dụng ngày đã chọn, hãy xem phần Sử dụng ngày đã chọn.
Bộ chọn ngày được cố định
Trong ví dụ sau, có một trường văn bản nhắc người dùng nhập ngày sinh. Khi họ nhấp vào biểu tượng lịch trong trường này, được gắn vào bộ chọn ngày bên dưới trường nhập dữ liệu.
@Composable fun DatePickerDocked() { var showDatePicker by remember { mutableStateOf(false) } val datePickerState = rememberDatePickerState() val selectedDate = datePickerState.selectedDateMillis?.let { convertMillisToDate(it) } ?: "" Box( modifier = Modifier.fillMaxWidth() ) { OutlinedTextField( value = selectedDate, onValueChange = { }, label = { Text("DOB") }, readOnly = true, trailingIcon = { IconButton(onClick = { showDatePicker = !showDatePicker }) { Icon( imageVector = Icons.Default.DateRange, contentDescription = "Select date" ) } }, modifier = Modifier .fillMaxWidth() .height(64.dp) ) if (showDatePicker) { Popup( onDismissRequest = { showDatePicker = false }, alignment = Alignment.TopStart ) { Box( modifier = Modifier .fillMaxWidth() .offset(y = 64.dp) .shadow(elevation = 4.dp) .background(MaterialTheme.colorScheme.surface) .padding(16.dp) ) { DatePicker( state = datePickerState, showModeToggle = false ) } } } } } @Composable fun DatePickerFieldToModal(modifier: Modifier = Modifier) { var selectedDate by remember { mutableStateOf<Long?>(null) } var showModal by remember { mutableStateOf(false) } OutlinedTextField( value = selectedDate?.let { convertMillisToDate(it) } ?: "", onValueChange = { }, label = { Text("DOB") }, placeholder = { Text("MM/DD/YYYY") }, trailingIcon = { Icon(Icons.Default.DateRange, contentDescription = "Select date") }, modifier = modifier .fillMaxWidth() .pointerInput(selectedDate) { awaitEachGesture { // Modifier.clickable doesn't work for text fields, so we use Modifier.pointerInput // in the Initial pass to observe events before the text field consumes them // in the Main pass. awaitFirstDown(pass = PointerEventPass.Initial) val upEvent = waitForUpOrCancellation(pass = PointerEventPass.Initial) if (upEvent != null) { showModal = true } } } ) if (showModal) { DatePickerModal( onDateSelected = { selectedDate = it }, onDismiss = { showModal = false } ) } } fun convertMillisToDate(millis: Long): String { val formatter = SimpleDateFormat("MM/dd/yyyy", Locale.getDefault()) return formatter.format(Date(millis)) }
Các điểm chính về mã
- Bộ chọn ngày xuất hiện khi người dùng nhấp vào
IconButton
.- Nút biểu tượng đóng vai trò là đối số cho tham số
trailingIcon
củaOutlinedTextField
. - Biến trạng thái
showDatePicker
kiểm soát chế độ hiển thị của bộ chọn ngày được gắn vào đế sạc.
- Nút biểu tượng đóng vai trò là đối số cho tham số
- Vùng chứa của bộ chọn ngày là một thành phần kết hợp
Popup
, phủ lên mà không ảnh hưởng đến bố cục của các phần tử khác. selectedDate
ghi lại giá trị của ngày đã chọn từ đối tượngDatePickerState
và định dạng giá trị đó bằng hàmconvertMillisToDate
.- Ngày đã chọn sẽ xuất hiện trong trường văn bản.
- Bộ chọn ngày được gắn vào vị trí bên dưới trường văn bản bằng
offset
đối tượng sửa đổi. Box
được dùng làm vùng chứa gốc để cho phép phân lớp văn bản thích hợp và bộ chọn ngày.
Kết quả
Sau khi bạn nhấp vào biểu tượng lịch, quá trình triển khai sẽ như sau:

Bộ chọn ngày mô-đun
Bộ chọn ngày theo phương thức phương thức hiển thị một hộp thoại nổi trên màn hình. Để triển khai
nó, hãy tạo DatePickerDialog
rồi truyền vào đó DatePicker
.
@Composable fun DatePickerModal( onDateSelected: (Long?) -> Unit, onDismiss: () -> Unit ) { val datePickerState = rememberDatePickerState() DatePickerDialog( onDismissRequest = onDismiss, confirmButton = { TextButton(onClick = { onDateSelected(datePickerState.selectedDateMillis) onDismiss() }) { Text("OK") } }, dismissButton = { TextButton(onClick = onDismiss) { Text("Cancel") } } ) { DatePicker(state = datePickerState) } }
Các điểm chính về mã
- Hàm có khả năng kết hợp
DatePickerModal
cho thấy một bộ chọn ngày ở chế độ. - Biểu thức lambda
onDateSelected
sẽ thực thi khi người dùng chọn một ngày.- Lớp này hiển thị ngày đã chọn cho thành phần kết hợp mẹ.
- Biểu thức lambda
onDismiss
thực thi khi người dùng đóng biểu thức .
Kết quả
Phương thức triển khai có dạng như sau:

Bộ chọn ngày cho cửa sổ phụ
Bộ chọn ngày theo phương thức bật lên có dữ liệu đầu vào sẽ hiển thị một hộp thoại nổi trên màn hình và cho phép người dùng nhập ngày.
@Composable fun DatePickerModalInput( onDateSelected: (Long?) -> Unit, onDismiss: () -> Unit ) { val datePickerState = rememberDatePickerState(initialDisplayMode = DisplayMode.Input) DatePickerDialog( onDismissRequest = onDismiss, confirmButton = { TextButton(onClick = { onDateSelected(datePickerState.selectedDateMillis) onDismiss() }) { Text("OK") } }, dismissButton = { TextButton(onClick = onDismiss) { Text("Cancel") } } ) { DatePicker(state = datePickerState) } }
Các điểm chính về mã
Thao tác này rất giống với ví dụ về bộ chọn ngày phụ. Chính như sau:
- Tham số
initialDisplayMode
đặt chế độ hiển thị ban đầu thànhDisplayMode.Input
.

Bộ chọn ngày có phạm vi
Bạn có thể tạo một bộ chọn ngày cho phép người dùng chọn một phạm vi giữa ngày bắt đầu và ngày kết thúc. Để thực hiện việc này, hãy sử dụng DateRangePicker
.
Việc sử dụng DateRangePicker
về cơ bản giống như DatePicker
. Bạn có thể sử dụng đối tượng này cho bộ chọn được neo dưới dạng phần tử con của PopUp
hoặc bạn có thể sử dụng đối tượng này làm bộ chọn phương thức và truyền đối tượng này đến DatePickerDialog
. Điểm khác biệt chính là bạn sử dụng DateRangePickerState
thay vì DatePickerState
.
Đoạn mã sau đây minh hoạ cách tạo bộ chọn ngày theo phương thức bật lên có phạm vi:
@Composable fun DateRangePickerModal( onDateRangeSelected: (Pair<Long?, Long?>) -> Unit, onDismiss: () -> Unit ) { val dateRangePickerState = rememberDateRangePickerState() DatePickerDialog( onDismissRequest = onDismiss, confirmButton = { TextButton( onClick = { onDateRangeSelected( Pair( dateRangePickerState.selectedStartDateMillis, dateRangePickerState.selectedEndDateMillis ) ) onDismiss() } ) { Text("OK") } }, dismissButton = { TextButton(onClick = onDismiss) { Text("Cancel") } } ) { DateRangePicker( state = dateRangePickerState, title = { Text( text = "Select date range" ) }, showModeToggle = false, modifier = Modifier .fillMaxWidth() .height(500.dp) .padding(16.dp) ) } }
Các điểm chính về mã
- Tham số
onDateRangeSelected
là một lệnh gọi lại nhận đượcPair<Long?, Long?>
đại diện cho ngày bắt đầu và ngày kết thúc đã chọn. Thao tác này cho phép thành phần kết hợp mẹ truy cập vào dải ô đã chọn. rememberDateRangePickerState()
tạo trạng thái cho phạm vi ngày bộ chọn.DatePickerDialog
tạo một vùng chứa hộp thoại phương thức.- Trong trình xử lý
onClick
của nút xác nhận,onDateRangeSelected
sẽ truyền phạm vi đã chọn lên thành phần kết hợp mẹ. - Thành phần kết hợp
DateRangePicker
đóng vai trò là nội dung hộp thoại.
Kết quả
Phương thức triển khai có dạng như sau:

Sử dụng ngày đã chọn
Để nắm bắt ngày đã chọn, hãy theo dõi ngày đó trong thành phần kết hợp mẹ dưới dạng Long
và
truyền giá trị đến DatePicker
trong onDateSelected
. Đoạn mã sau
minh hoạ điều này, mặc dù bạn có thể xem cách triển khai đầy đủ trong tệp chính thức
đoạn mã ứng dụng.
// ... var selectedDate by remember { mutableStateOf<Long?>(null) } // ... if (selectedDate != null) { val date = Date(selectedDate!!) val formattedDate = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()).format(date) Text("Selected date: $formattedDate") } else { Text("No date selected") } // ... DatePickerModal( onDateSelected = { selectedDate = it showModal = false }, onDismiss = { showModal = false } ) } // ...
Về cơ bản, công cụ này áp dụng tương tự cho bộ chọn ngày theo phạm vi, mặc dù bạn cần
sử dụng Pair<Long?, Long?>
hoặc lớp dữ liệu để thu thập giá trị bắt đầu và giá trị kết thúc.