Инструменты выбора даты позволяют пользователям выбирать дату, диапазон дат или и то, и другое. Для выбора дат используются диалоговое окно календаря или текстовое поле ввода.
Типы
Существует три типа программ для выбора дат:
- Закрепленный : отображается непосредственно в макете. Подходит для компактных макетов, где отдельное диалоговое окно может показаться навязчивым.
- Модальное окно : Отображается в виде диалогового окна, наложенного поверх содержимого приложения. Это позволяет четко сфокусироваться на выборе даты.
- Модальное поле ввода : объединяет текстовое поле с модальным окном выбора даты.
Вы можете реализовать эти средства выбора даты в своем приложении, используя следующие составные элементы:
-
DatePicker: Универсальный компонент для выбора даты. Используемый контейнер определяет, будет ли он закреплен или отображаться в виде модели. -
DatePickerDialog: Контейнер для модального окна и модального поля ввода даты. -
DateRangePicker: Подходит для любого средства выбора даты, где пользователь может выбрать диапазон с начальной и конечной датами.
Состояние
Ключевым параметром, общим для всех составных элементов выбора даты, является state , который принимает либо объект DatePickerState , либо DateRangePickerState . Их свойства содержат информацию о выборе пользователя с помощью средства выбора даты, например, о текущей выбранной дате.
Для получения более подробной информации о том, как использовать выбранную дату, см. раздел «Использование выбранной даты» .
закрепленный элемент выбора даты
В следующем примере представлено текстовое поле, в котором пользователю предлагается ввести дату своего рождения. При нажатии на значок календаря в этом поле открывается встроенное окно выбора даты под полем ввода.
@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)) }
Основные моменты, касающиеся кода.
- Поле выбора даты появляется, когда пользователь нажимает на
IconButton.- Кнопка с иконкой служит аргументом для параметра
trailingIconобъектаOutlinedTextField. - Переменная состояния
showDatePickerуправляет видимостью закрепленного элемента выбора даты.
- Кнопка с иконкой служит аргументом для параметра
- Контейнер для выбора даты представляет собой составной
Popup, который накладывается поверх содержимого, не влияя на расположение других элементов. -
selectedDateизвлекает значение выбранной даты из объектаDatePickerStateи форматирует его с помощью функцииconvertMillisToDate. - Выбранная дата отобразится в текстовом поле.
- Встроенный элемент выбора даты располагается под текстовым полем с помощью модификатора
offset. - В качестве корневого контейнера используется
Box, позволяющий корректно располагать текстовое поле и средство выбора даты.
Результаты
После нажатия на значок календаря отображается следующее:

Модальный выбор даты
Модальное окно выбора даты отображает диалоговое окно, которое плавает над экраном. Для его реализации создайте объект DatePickerDialog и передайте ему объект 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) } }
Основные моменты, касающиеся кода.
- Композитная функция
DatePickerModalотображает модальное окно выбора даты. - Лямбда-выражение
onDateSelectedвыполняется, когда пользователь выбирает дату.- Это позволяет родительскому компоненту отображать выбранную дату.
- Лямбда-выражение
onDismissвыполняется, когда пользователь закрывает диалоговое окно.
Результаты
Данная реализация выглядит следующим образом:

Модальное поле ввода для выбора даты
Модальное окно выбора даты с полем ввода отображает диалоговое окно, которое плавает над экраном и позволяет пользователю ввести дату.
@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) } }
Основные моменты, касающиеся кода.
Это очень похоже на пример с модальным окном выбора даты . Основное отличие заключается в следующем:
- Параметр
initialDisplayModeустанавливает начальный режим отображения вDisplayMode.Input.

Выбор даты с диапазоном
Вы можете создать средство выбора даты, которое позволит пользователю выбрать диапазон между начальной и конечной датой. Для этого используйте DateRangePicker .
Использование DateRangePicker по сути аналогично использованию DatePicker . Вы можете использовать его в качестве дочернего элемента для закрепленного элемента выбора даты PopUp или в качестве модального элемента выбора даты (Modal Picker) и передать его в DatePickerDialog . Основное отличие заключается в том, что вместо DatePickerState используется DateRangePickerState .
Следующий фрагмент кода демонстрирует, как создать модальное окно выбора даты с диапазоном значений:
@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) ) } }
Основные моменты, касающиеся кода.
- Параметр
onDateRangeSelected— это функция обратного вызова, которая принимает объектPair<Long?, Long?>, представляющий выбранные начальную и конечную даты. Это обеспечивает родительскому компоненту доступ к выбранному диапазону. -
rememberDateRangePickerState()создает состояние для средства выбора диапазона дат. - Компонент
DatePickerDialogсоздает модальный диалоговый контейнер. - В обработчике события
onClickкнопки подтвержденияonDateRangeSelectedпередает выбранный диапазон родительскому компоненту. - Компонент
DateRangePickerслужит содержимым диалогового окна.
Результаты
Данная реализация выглядит следующим образом:

Использовать выбранную дату
Чтобы получить выбранную дату, отслеживайте её в родительском компоненте как тип Long и передавайте значение в DatePicker в onDateSelected . Следующий фрагмент кода демонстрирует это, хотя полную реализацию можно увидеть в официальном приложении с фрагментами кода .
// ... 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 } ) } // ...
По сути, то же самое относится и к средствам выбора диапазона дат , хотя для получения начального и конечного значений вам потребуется использовать Pair<Long?, Long?> или класс данных.