如何阻止Material日期范围选择器选中相同日期?
实现Material Date Range Picker的两个自定义功能
1. 阻止选中相同的起始与结束日期
要实现这个需求,你需要自定义CalendarConstraints.DateValidator来校验日期范围,确保起始和结束日期不重合:
class DifferentDateValidator : CalendarConstraints.DateValidator { override fun isValid(date: Long): Boolean { return true } override fun writeToParcel(parcel: Parcel, flags: Int) {} override fun describeContents(): Int = 0 companion object CREATOR : Parcelable.Creator<DifferentDateValidator> { override fun createFromParcel(parcel: Parcel): DifferentDateValidator { return DifferentDateValidator() } override fun newArray(size: Int): Array<DifferentDateValidator?> { return arrayOfNulls(size) } } // 校验选中的日期范围是否合法 fun isRangeValid(start: Long?, end: Long?): Boolean { return if (start != null && end != null) { // 转换为UTC时区避免时区差异导致的判断错误 val startCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply { timeInMillis = start } val endCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply { timeInMillis = end } // 判断是否为同一天 !(startCalendar.get(Calendar.YEAR) == endCalendar.get(Calendar.YEAR) && startCalendar.get(Calendar.DAY_OF_YEAR) == endCalendar.get(Calendar.DAY_OF_YEAR)) } else { // 未选完范围时默认合法 true } } }
接着在构建CalendarConstraints时,结合这个自定义校验器和已有的DateValidatorPointBackward:
val differentDateValidator = DifferentDateValidator() val calendarConstraints = CalendarConstraints.Builder() .setValidator(object : CalendarConstraints.DateValidator { private val backwardValidator = DateValidatorPointBackward.now() override fun isValid(date: Long): Boolean { return backwardValidator.isValid(date) } override fun writeToParcel(parcel: Parcel, flags: Int) {} override fun describeContents(): Int = 0 override fun isValid(start: Long?, end: Long?): Boolean { // 同时满足向后校验和日期不重复校验 return backwardValidator.isValid(start, end) && differentDateValidator.isRangeValid(start, end) } }) .build()
2. 再次选择起始日期时重置已选范围
通过给MaterialDatePicker设置OnSelectionChangeListener,监听选择变化,当用户重新选择起始日期时清空结束日期:
private fun showDateRangePicker() { var previousStartDate: Long? = null val differentDateValidator = DifferentDateValidator() val calendarConstraints = CalendarConstraints.Builder() .setValidator(object : CalendarConstraints.DateValidator { private val backwardValidator = DateValidatorPointBackward.now() override fun isValid(date: Long): Boolean { return backwardValidator.isValid(date) } override fun writeToParcel(parcel: Parcel, flags: Int) {} override fun describeContents(): Int = 0 override fun isValid(start: Long?, end: Long?): Boolean { return backwardValidator.isValid(start, end) && differentDateValidator.isRangeValid(start, end) } }) .build() val dateRangePicker = MaterialDatePicker.Builder.dateRangePicker() .setTitleText(getString(R.string.date_picker_title)) .setTheme(R.style.MaterialCalendarTheme_RangeFill) .setCalendarConstraints(calendarConstraints) .setSelection(setSelection) .build() // 监听选择变化,实现重置逻辑 dateRangePicker.addOnSelectionChangeListener { selection -> val currentStart = selection.first val currentEnd = selection.second if (currentStart != null && currentStart != previousStartDate) { // 用户重新选择了起始日期,清空结束日期 dateRangePicker.selection = Pair(currentStart, null) previousStartDate = currentStart } } dateRangePicker.show(parentFragmentManager, "Tag") }
关键说明
- 自定义校验器通过重写
isValid(start: Long?, end: Long?)方法,直接判断起止日期是否为同一天,拒绝非法选择。 - 选择监听器通过记录上一次的起始日期,当用户选择新的起始日期时,强制将结束日期置空,实现范围重置的效果。
内容的提问来源于stack exchange,提问作者misterios
相关产品推荐
相关产品推荐

