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

Android Kotlin中如何禁用DatePickerDialog指定及多个日期

在Kotlin中实现DatePickerDialog禁用指定日期并设置日期范围

首先要明确:原生Android的DatePickerDialog本身没有setDisabledDays()方法,这就是你代码里调用该方法无效的核心原因。要实现禁用指定日期+设置日期范围的需求,推荐使用Material组件库提供的MaterialDatePicker(功能更完善),也可以通过自定义原生Dialog实现,下面分两种方案说明:

方案一:使用MaterialDatePicker(推荐)

Material组件库的MaterialDatePicker原生支持禁用指定日期,同时能轻松设置日期范围,步骤如下:

  1. 确保项目引入Material组件依赖(在Module级别的build.gradle文件中):
implementation 'com.google.android.material:material:1.9.0' // 版本可按需更新
  1. 实现核心代码:
fun showDatePicker() {
    // 1. 构建日期范围约束
    val constraintsBuilder = CalendarConstraints.Builder()
    // 设置最小日期(示例:当前日期前30天)
    val minDate = Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, -30) }.timeInMillis
    // 设置最大日期(示例:当前日期后30天)
    val maxDate = Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, 30) }.timeInMillis
    constraintsBuilder.setStart(minDate)
    constraintsBuilder.setEnd(maxDate)

    // 2. 定义要禁用的日期集合(转为毫秒时间戳)
    val disabledDates = mutableListOf<Long>().apply {
        add(getTimestampFromDate(2023, 8, 22)) // 2023-08-22
        add(getTimestampFromDate(2023, 8, 12)) // 2023-08-12
        add(getTimestampFromDate(2023, 8, 15)) // 2023-08-15
    }

    // 3. 设置日期禁用规则
    constraintsBuilder.setValidator(object : CalendarConstraints.DateValidator {
        override fun isValid(date: Long): Boolean {
            return !disabledDates.contains(date)
        }

        override fun writeToParcel(parcel: Parcel, flags: Int) {}
        override fun describeContents(): Int = 0
    })

    // 4. 创建并显示日期选择器
    val datePicker = MaterialDatePicker.Builder.datePicker()
        .setCalendarConstraints(constraintsBuilder.build())
        .setTitleText("选择日期")
        .build()

    // 处理选中日期的回调
    datePicker.addOnPositiveButtonClickListener { selectedDate ->
        val calendar = Calendar.getInstance().apply { timeInMillis = selectedDate }
        val year = calendar.get(Calendar.YEAR)
        val month = calendar.get(Calendar.MONTH) + 1 // 转为1-12的月份格式
        val day = calendar.get(Calendar.DAY_OF_MONTH)
        // 这里添加你的业务逻辑
    }

    datePicker.show(supportFragmentManager, "DATE_PICKER_TAG")
}

// 辅助方法:将年、月(1-12)、日转为标准毫秒时间戳
private fun getTimestampFromDate(year: Int, month: Int, day: Int): Long {
    return Calendar.getInstance().apply {
        set(Calendar.YEAR, year)
        set(Calendar.MONTH, month - 1) // Calendar的月份为0-11,需转格式
        set(Calendar.DAY_OF_MONTH, day)
        set(Calendar.HOUR_OF_DAY, 0)
        set(Calendar.MINUTE, 0)
        set(Calendar.SECOND, 0)
        set(Calendar.MILLISECOND, 0)
    }.timeInMillis
}

方案二:自定义原生DatePickerDialog(繁琐,不推荐)

原生DatePicker没有直接禁用日期的API,需要通过拦截日期选择事件实现,步骤如下:

  1. 创建自定义Dialog类:
class CustomDatePickerDialog(
    context: Context,
    private val disabledDates: List<Calendar>,
    listener: OnDateSetListener,
    year: Int,
    month: Int,
    day: Int
) : DatePickerDialog(context, listener, year, month, day) {

    override fun onDateChanged(view: DatePicker, year: Int, month: Int, day: Int) {
        val selectedCalendar = Calendar.getInstance().apply {
            set(year, month, day)
            set(Calendar.HOUR_OF_DAY, 0)
            set(Calendar.MINUTE, 0)
            set(Calendar.SECOND, 0)
            set(Calendar.MILLISECOND, 0)
        }

        // 检查选中日期是否在禁用列表中
        val isDisabled = disabledDates.any {
            it.get(Calendar.YEAR) == selectedCalendar.get(Calendar.YEAR) &&
                    it.get(Calendar.MONTH) == selectedCalendar.get(Calendar.MONTH) &&
                    it.get(Calendar.DAY_OF_MONTH) == selectedCalendar.get(Calendar.DAY_OF_MONTH)
        }

        if (isDisabled) {
            // 禁用日期时重置到当前日期并提示
            val currentCalendar = Calendar.getInstance()
            updateDate(
                currentCalendar.get(Calendar.YEAR),
                currentCalendar.get(Calendar.MONTH),
                currentCalendar.get(Calendar.DAY_OF_MONTH)
            )
            Toast.makeText(context, "该日期不可选", Toast.LENGTH_SHORT).show()
        } else {
            super.onDateChanged(view, year, month, day)
        }
    }
}
  1. 使用自定义Dialog:
fun datepicker() {
    val year = Calendar.getInstance().get(Calendar.YEAR)
    val month = Calendar.getInstance().get(Calendar.MONTH)
    val day = Calendar.getInstance().get(Calendar.DAY_OF_MONTH)

    // 构建禁用日期的Calendar集合
    val disabledCalendars = listOf(
        Calendar.getInstance().apply { set(2023, 7, 22) }, // 2023-08-22(月份为0-11)
        Calendar.getInstance().apply { set(2023, 7, 12) }, // 2023-08-12
        Calendar.getInstance().apply { set(2023, 7, 15) }  // 2023-08-15
    )

    val datePickerDialog = CustomDatePickerDialog(
        this,
        disabledCalendars,
        { view, year, monthOfYear, dayOfMonth ->
            // 处理选中日期的业务逻辑
        },
        year, month, day
    )

    // 设置最小、最大日期范围
    val minDate = Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, -30) }.timeInMillis
    val maxDate = Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, 30) }.timeInMillis
    datePickerDialog.datePicker.minDate = minDate
    datePickerDialog.datePicker.maxDate = maxDate

    datePickerDialog.show()
}

关键提示

  • 处理日期时注意Calendar的月份是0-11,设置8月时要传入7,避免日期错误。
  • 优先选择MaterialDatePicker,它是官方推荐的组件,无需复杂自定义即可实现所有需求。

内容的提问来源于stack exchange,提问作者Rahul Routh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 17:55:16