You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 09:10:32