日期选择器 允许用户选择一个日期、一个日期范围或两者。它们使用日历对话框或文本输入来允许用户选择日期。
类型
有三种类型的日期选择器
- 停靠式:显示在布局中的内联区域。它适用于紧凑型布局,在这种布局中,专用对话框可能会显得过于突兀。
- 模态:以对话框的形式显示,覆盖应用程序内容。这将为日期选择提供清晰的焦点。
- 模态输入:将文本字段与模态日期选择器结合在一起。
您可以使用以下可组合项在您的应用中实现这些日期选择器
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 ) } } } } } fun convertMillisToDate(millis: Long): String { val formatter = SimpleDateFormat("MM/dd/yyyy", Locale.getDefault()) return formatter.format(Date(millis)) }
关于代码的关键点
- 当用户点击
IconButton
时,日期选择器将出现。- 图标按钮作为
OutlinedTextField
的trailingIcon
参数的参数。 - 状态变量
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
显示模态日期选择器。 - 当用户选择日期时,lambda 表达式
onDateSelected
将执行。- 它将所选日期公开给父可组合项。
- 当用户关闭对话框时,lambda 表达式
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
的子项,用作 停靠式选择器,也可以将其用作 模态选择器 并将其传递给 DatePickerDialog
。主要区别在于您使用的是 DateRangePickerState
而不是 DatePickerState
.
以下代码片段演示了如何创建带有范围的模态日期选择器
@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
并将值传递给 onDateSelected
中的 DatePicker
。以下代码片段演示了这一点,但是您可以在 官方代码片段应用 中看到完整实现。
// ... 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?>
或数据类来捕获开始值和结束值。