Dhia Shalabi
Dhia Shalabi

Reputation: 1540

How to set min or max date for material datepicker

I'm using google material DatePicker and I want to set min and max date for the picker it self! This is my code

private fun getDatPikr(tv: MaterialTextView, title: String, pastDays: Boolean = false) {
        val datePicker = MaterialDatePicker.Builder.datePicker()
                .setTitleText(title)
                .build()
        
        datePicker.show(childFragmentManager, "MATERIAL_DATE_PICKER")
        datePicker.addOnPositiveButtonClickListener {
            val calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
            calendar.time = Date(it)
            val date = "${calendar.get(Calendar.DAY_OF_MONTH)}/ " +
                    "${calendar.get(Calendar.MONTH) + 1}/${calendar.get(Calendar.YEAR)}"
            tv.text = date
        }
    }

Upvotes: 5

Views: 10722

Answers (5)

Abhishek Tiwari
Abhishek Tiwari

Reputation: 304

I got a requirement to show calendar only 50 years back from the current date and 50 years ahead from current date. I achieved this using MaterialDatePicker.

For instance: if current date is 27/07/2022
Then my Min Date would be: 27/07/1972
And Max Date would be: 27/07/2072

Here's the code:

private var mSelectedDate: Long = MaterialDatePicker.todayInUtcMilliseconds()

binding.btnPickDate.setOnClickListener {
            val cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
            val today = MaterialDatePicker.todayInUtcMilliseconds()
            cal.timeInMillis = today
            cal.set(cal[Calendar.YEAR] - 50, cal[Calendar.MONTH], cal[Calendar.DATE])
            val fiftyYearsBack = cal.timeInMillis
            cal.timeInMillis = today
            cal.set(cal[Calendar.YEAR] + 50, cal[Calendar.MONTH], cal[Calendar.DATE])
            val fiftyYearsAhead = cal.timeInMillis

            val datePicker =
                MaterialDatePicker.Builder.datePicker()
                    .setTitleText("Select date")
                    .setInputMode(MaterialDatePicker.INPUT_MODE_CALENDAR)
                    .setSelection(mSelectedDate)
                    .setTheme(R.style.Widget_AppTheme_MaterialDatePicker)
                    .setCalendarConstraints(
                        CalendarConstraints.Builder()
                            .setStart(fiftyYearsBack)
                            .setEnd(fiftyYearsAhead)
                            .setValidator(
                                DateValidatorFiftyYearRange(
                                    fiftyYearsBack,
                                    fiftyYearsAhead
                                )
                            )
                            .build()
                    ).build()
            datePicker.show(supportFragmentManager, "DP")
            datePicker.addOnPositiveButtonClickListener {
                val sdf = SimpleDateFormat("dd/MM/yyyy", Locale.US)
                mSelectedDate = it
            }
        }

And for the DateValidatorFiftyYearRange class

import android.os.Parcel
import android.os.Parcelable
import com.google.android.material.datepicker.CalendarConstraints.DateValidator

/**
 * A {@link DateValidator} that allows only 50 years back and forth from the current date.
 */
class DateValidatorFiftyYearRange(private val start: Long, private val end: Long) : DateValidator {

    override fun describeContents(): Int {
        return 0
    }

    override fun writeToParcel(p0: Parcel?, p1: Int) {
        p0?.writeLong(start)
        p0?.writeLong(end)
    }

    override fun isValid(date: Long): Boolean {
        return date in start..end
    }

    override fun equals(other: Any?): Boolean {
        return if (this === other) {
            true
        } else other is DateValidatorFiftyYearRange
    }

    override fun hashCode(): Int {
        val hashedFields = arrayOf<Any>(start, end)
        return hashedFields.contentHashCode()
    }

    companion object CREATOR : Parcelable.Creator<DateValidatorFiftyYearRange> {
        override fun createFromParcel(parcel: Parcel): DateValidatorFiftyYearRange {
            return DateValidatorFiftyYearRange(parcel)
        }

        override fun newArray(size: Int): Array<DateValidatorFiftyYearRange?> {
            return arrayOfNulls(size)
        }
    }

    constructor(parcel: Parcel) : this(parcel.readLong(), parcel.readLong())
}

And here's the style, just in case if you want to hide edit pen button on calendar:

<style name="Widget.AppTheme.MaterialDatePicker" parent="ThemeOverlay.MaterialComponents.MaterialCalendar">
        <item name="materialCalendarHeaderToggleButton">@style/Widget.AppTheme.MaterialCalendar.HeaderToggleButton</item>
    </style>

    <style name="Widget.AppTheme.MaterialCalendar.HeaderToggleButton" parent="Widget.MaterialComponents.MaterialCalendar.HeaderToggleButton">
        <item name="android:visibility">gone</item>
    </style>

Upvotes: 1

Geek Tanmoy
Geek Tanmoy

Reputation: 870

As per new Material Date pickers we can set the end date by passing setValidater() in Calendar Constraints.

val constraintsBuilder=CalendarConstraints.Builder()
            .setValidator(DateValidatorPointBackward.now())

So that the user can only select the backwards dates from today or any date.

Upvotes: 16

Muhammad Muaaz Farooq
Muhammad Muaaz Farooq

Reputation: 211

Try this

val constraint = CalendarConstraints.Builder()
        .setValidator(DateValidatorPointBackward.before(Calendar.getInstance().timeInMillis - YEAR_18_IN_MILLI))
    val datePicker = MaterialDatePicker.Builder.datePicker()
        .setCalendarConstraints(constraint.build())
        .setSelection(YEAR_18_IN_MILLI)
        .setTitleText(getString(R.string.date_of_birth))
        .build()

Upvotes: 2

SpiritCrusher
SpiritCrusher

Reputation: 21053

You can use CalendarConstraints to set configuration . Something like below.

 val calendar = Calendar.getInstance()
    val upTo = calendar.timeInMillis
    calendar.set(2020, 1, 15)
    val startFrom = calendar.timeInMillis
    val constraints =CalendarConstraints.Builder()
        .setStart(startFrom)
        .setEnd(upTo)
        .build()
    val datePicker = MaterialDatePicker.Builder.datePicker()
        .setCalendarConstraints(constraints)
        .setTitleText("title")
        .build()

You can Also add a validator to constraints by implementing CalendarConstraints.DateValidator . This will prevent the invalid date selection . Give it a try its showing some weird behavior on my device .
Found Similar thread. have a look at This thread.

Upvotes: 3

Please check the doc Min and Max

You can also do it from the code using this method:

datePicker.setMinDate("Set the min date in millis")

datePicker.setMaxDate("Set the max date in millis")

Check this answer: here

Upvotes: -2

Related Questions