一、概念
一般是以对话框的形式呼出,DatePickerDialog 就是对 DatePicker 的一个简单对话框封装。
@Composable todayDateBorderColor = Color.Red //默认选中的当天日期的边框色 selectedDayContentColor = Color.Red //选中的文字颜色 selectedDayContainerColor = Color.Red //选中的填充颜色 ) |
@Composable |
输入模式 | 选择模式 |
二、基本使用
2.1 获取状态
2.1.1 单个日期选择 rememberDatePickerState()
@Composable fun rememberDatePickerState( @Suppress("AutoBoxing") initialSelectedDateMillis: Long? = null, //默认选中的日期 @Suppress("AutoBoxing") initialDisplayedMonthMillis: Long? = initialSelectedDateMillis, //默认显示的月份 yearRange: IntRange = DatePickerDefaults.YearRange, //限制选择的年份范围,如 2000..2100 initialDisplayMode: DisplayMode = DisplayMode.Picker //选择模式Picker、输入模式Input ): DatePickerState |
2.1.2 范围日期选择 rememberDateRangePickerState()
@Composable fun rememberDateRangePickerState( @Suppress("AutoBoxing") initialSelectedStartDateMillis: Long? = null, //起始日期 @Suppress("AutoBoxing") initialSelectedEndDateMillis: Long? = null, //结束日期 @Suppress("AutoBoxing") initialDisplayedMonthMillis: Long? = initialSelectedStartDateMillis, //默认显示的月份(如果起始日期没指定就默认是当月) yearRange: IntRange = DatePickerDefaults.YearRange, //允许选择的年份,如 2000..2100 initialDisplayMode: DisplayMode = DisplayMode.Picker //选择模式Picker、输入模式Input ): DateRangePickerState |
2.1.3 自定义可选择日期 selectableDates
Compose Material3 1.2.0-alpha02 及其以上版本,提供了一个 selectableDates 参数,可以在其中完全自定义可以选择的日期。
val datePickerState = rememberDatePickerState(
selectableDates = object : SelectableDates {
// 禁止选择周末(周六和周日)
override fun isSelectableDate(utcTimeMillis: Long): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val dayOfWeek = Instant.ofEpochMilli(utcTimeMillis).atZone(ZoneId.of("UTC"))
.toLocalDate().dayOfWeek
dayOfWeek != DayOfWeek.SUNDAY && dayOfWeek != DayOfWeek.SATURDAY
} else {
val calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
calendar.timeInMillis = utcTimeMillis
calendar[Calendar.DAY_OF_WEEK] != Calendar.SUNDAY &&
calendar[Calendar.DAY_OF_WEEK] != Calendar.SATURDAY
}
}
// 只允许选择2023年以前
override fun isSelectableYear(year: Int): Boolean {
return year > 2022
}
}
)
2.2 DatePicker
val datePickerState = rememberDatePickerState()
DatePicker(state = datePickerState)
Text("当前选中日期的时间戳 ${datePickerState.selectedDateMillis ?: "没有选择"}")
2.3 DatePickerDialog
var isOpenDialog by remember { mutableStateOf(false) }
val datePickerState = rememberDatePickerState()
val sdf = remember { SimpleDateFormat("yyy-MM-dd") }
if (isOpenDialog) {
DatePickerDialog(
onDismissRequest = { isOpenDialog = false},
colors = DatePickerDefaults.colors(containerColor = AppColors.White), //背景色(这个在下面的DatePicker中设置无效)
confirmButton = {
Text(
modifier = Modifier
.clickableNoRipple {
//拿到的是时间戳,需要格式化
val date = datePickerState.selectedDateMillis
if (date != null) {
onValueChange(sdf.format(date))
isDefaultValue = false
}
isOpenDialog = false
},
text = "确定",
)
},
dismissButton = {
Text(
modifier = Modifier.clickableNoRipple { isOpenDialog = false },
text = "取消"
)
}
) {
DatePicker(
state = datePickerState,
colors = DatePickerDefaults.colors(
todayDateBorderColor = AppColors.Primary, //默认选中的当天日期的边框色
selectedDayContentColor = AppColors.White, //选中的文字颜色
selectedDayContainerColor = AppColors.Primary, //选中的填充颜色
)
)
}
}
三、封装
3.1 单按钮时间选择对话框
@Preview
@Composable
private fun SingleButtonDatePickerPreView() {
var value by remember { mutableStateOf("选择时间") }
SingleButtonDatePickerView(
value = value,
onValueChange = { value = it },
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SingleButtonDatePickerView(
modifier: Modifier = Modifier,
value: String = "选择时间",
onValueChange: (String) -> Unit,
borderColor: Color = AppColors.Hint,
) {
var isOpenDialog by remember { mutableStateOf(false) }
var isDefaultValue by remember { mutableStateOf(true) }
val datePickerState = rememberDatePickerState()
val sdf = remember { SimpleDateFormat("yyy-MM-dd") }
Row(
modifier = modifier
.height(AppDimens.heightButton)
.border(
width = 1.dp,
color = borderColor,
shape = RoundedCornerShape(AppDimens.radius)
)
.padding(horizontal = AppDimens.paddingContent)
.clickableNoRipple { isOpenDialog = true },
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = value,
maxLines = 1,
color = if(isDefaultValue) AppColors.Hint else AppColors.Black,
fontSize = AppDimens.textPrimary,
)
Icon(
modifier = Modifier.padding(start = 5.dp),
imageVector = Icons.Default.CalendarMonth,
contentDescription = null,
tint = AppColors.Hint
)
}
if (isOpenDialog) {
DatePickerDialog(
onDismissRequest = { isOpenDialog = false},
colors = DatePickerDefaults.colors(containerColor = AppColors.White), //背景色(这个在下面的DatePicker中设置无效)
confirmButton = {
Text(
modifier = Modifier
.clickableNoRipple {
val date = datePickerState.selectedDateMillis
if (date != null) {
onValueChange(sdf.format(date))
isDefaultValue = false
} else {
isDefaultValue = true
}
isOpenDialog = false
}
.padding(end = 20.dp),
text = "确定",
color = AppColors.Primary,
fontSize = AppDimens.textTitle
)
},
dismissButton = {
Text(
modifier = Modifier
.clickableNoRipple {
isOpenDialog = false
}
.padding(end = 20.dp),
text = "取消",
color = AppColors.textGray,
fontSize = AppDimens.textTitle
)
}
) {
DatePicker(
state = datePickerState,
colors = DatePickerDefaults.colors(
todayDateBorderColor = AppColors.Primary, //默认选中的当天日期的边框色
selectedDayContentColor = AppColors.White, //选中的文字颜色
selectedDayContainerColor = AppColors.Primary, //选中的填充颜色
)
)
}
}
}
3.2 双按钮时间选择对话框
@Preview
@Composable
private fun TwoButtonDatePickerPreview() {
var startDate by remember { mutableStateOf("开始时间") }
var endDate by remember { mutableStateOf("结束时间") }
TwoButtonDatePickerView(
startDate = startDate,
endDate = endDate,
onStartChange = { startDate = it },
onEndChange = { endDate = it },
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TwoButtonDatePickerView(
modifier: Modifier = Modifier,
startDate: String = "开始时间",
endDate: String = "结束时间",
onStartChange: (String) -> Unit,
onEndChange: (String) -> Unit,
borderColor: Color = AppColors.Hint,
) {
var isOpenStartDialog by remember { mutableStateOf(false) }
var isOpenEndDialog by remember { mutableStateOf(false) }
val startDatePickerState = rememberDatePickerState()
val endDatePickerState = rememberDatePickerState()
var isStartDateDefault by remember { mutableStateOf(true) }
var isEndDateDefault by remember { mutableStateOf(true) }
val sdf = remember { SimpleDateFormat("yyy-MM-dd") }
Row(
modifier = modifier
.height(AppDimens.heightButton)
.border(
width = 1.dp,
color = borderColor,
shape = RoundedCornerShape(AppDimens.radius)
)
.padding(horizontal = AppDimens.paddingContent),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
modifier = Modifier.clickableNoRipple { isOpenStartDialog = true },
text = startDate,
color = if (isStartDateDefault) AppColors.Hint else AppColors.Black,
maxLines = 1,
fontSize = AppDimens.textPrimary
)
Icon(
modifier = Modifier
.size(25.dp)
.padding(horizontal = 5.dp),
painter = painterResource(id = R.drawable.icon_arrow_right),
contentDescription = null,
tint = AppColors.Hint
)
Text(
modifier = Modifier.clickableNoRipple { isOpenEndDialog = true },
text = endDate,
color = if (isEndDateDefault) AppColors.Hint else AppColors.Black,
maxLines = 1,
fontSize = AppDimens.textPrimary
)
Icon(
modifier = Modifier.padding(start = 5.dp),
imageVector = Icons.Default.CalendarMonth,
contentDescription = null,
tint = AppColors.Hint
)
}
if (isOpenStartDialog) {
DatePickerDialog(
onDismissRequest = { isOpenStartDialog = false},
colors = DatePickerDefaults.colors(containerColor = AppColors.White),
confirmButton = {
Text(
modifier = Modifier
.clickableNoRipple {
val date = startDatePickerState.selectedDateMillis
if (date != null) {
onStartChange(sdf.format(date))
isStartDateDefault = false
} else {
isStartDateDefault = true
}
isOpenStartDialog = false
}
.padding(end = 20.dp),
text = "确定",
color = AppColors.Primary,
fontSize = AppDimens.textTitle
)
},
dismissButton = {
Text(
modifier = Modifier
.clickableNoRipple {
isOpenStartDialog = false
}
.padding(end = 20.dp),
text = "取消",
color = AppColors.textGray,
fontSize = AppDimens.textTitle
)
}
) {
DatePicker(
state = startDatePickerState,
colors = DatePickerDefaults.colors(
todayDateBorderColor = AppColors.Primary,
selectedDayContentColor = AppColors.White,
selectedDayContainerColor = AppColors.Primary,
)
)
}
}
if (isOpenEndDialog) {
DatePickerDialog(
onDismissRequest = { isOpenEndDialog = false},
colors = DatePickerDefaults.colors(containerColor = AppColors.White),
confirmButton = {
Text(
modifier = Modifier
.clickableNoRipple {
val date = endDatePickerState.selectedDateMillis
if (date != null) {
onEndChange(sdf.format(date))
isEndDateDefault = false
} else {
isEndDateDefault = true
}
isOpenEndDialog = false
}
.padding(end = 20.dp),
text = "确定",
color = AppColors.Primary,
fontSize = AppDimens.textTitle
)
},
dismissButton = {
Text(
modifier = Modifier
.clickableNoRipple {
isOpenEndDialog = false
}
.padding(end = 20.dp),
text = "取消",
color = AppColors.textGray,
fontSize = AppDimens.textTitle
)
}
) {
DatePicker(
state = endDatePickerState,
colors = DatePickerDefaults.colors(
containerColor = AppColors.White,
todayDateBorderColor = AppColors.Primary,
selectedDayContentColor = AppColors.White,
selectedDayContainerColor = AppColors.Primary,
)
)
}
}
}