Android Kotlin

Everything You Need To Know About New Android Material Design Date Picker

Google+ Pinterest LinkedIn Tumblr

Today, almost every android application has some kind of date or time picker implemented. We often use them to set reminders, mark special dates in the calendar, set up an alarm, etc… Nowadays almost every app developer tries to follow the Material guidelines and luckily with the recent release of Google Material Design library we can use the MaterialDatePicker component. It a new component that has very compelling features including the following list.

Before showing you the features you need to add the updated Material Design library in the app-level build.gradle file.

    implementation 'com.google.android.material:material:1.2.0-alpha04'

Table of contents:

Simple Material Calendar Date Picker

This Material DatePicker is the default one (Mostly used when you want to select only one date).

val builder : MaterialDatePicker.Builder<*> = MaterialDatePicker.Builder.datePicker() // 1
val picker : MaterialDatePicker<*> = builder.build()  // 2
picker.show(supportFragmentManager, picker.toString())   // 3

Here, what’s going on inside the above code.

  1. Creating a MaterialDatePicker.Builder instance that gives us a single date selector.
  2. Building-up the MaterialDatePicker by calling a builder.build function.
  3. Display the Material Date Picker.

Here’s what it looks like!

Show Default Android Material Date Picker

If you look at the OK (Positive) button at the bottom you’ll notice that it’s by default not enable until we select the date from the Date Picker. So, here’s how to select the default date when the dialog shows.

val builder : MaterialDatePicker.Builder<*> = MaterialDatePicker.Builder.datePicker()
val currentTimeInMillis = Calendar.getInstance().timeInMillis
builder.setSelection(currentTimeInMillis) 
val picker : MaterialDatePicker<*> = builder.build()
picker.show(supportFragmentManager, picker.toString()) 

Now if we run the above code the Android Material Date Picker by-default shows with the today date as selected.

Show Default Android Material Date Picker with selection date

That’s cool! I think at this point you guys understand how simple it is to show a Date Picker using Material Design Library. Let’s take this example a little further and see how we can restrict the user to select a date within the start and end date.

Restrict User To SELECT The Date Within Start & End Date

We often have this business logic to only show the calendar dates within the date ranges and it’s a nightmare to do it. Well Not Now!

val constraintsBuilder = CalendarConstraints.Builder()  // 1
val calendar = Calendar.getInstance()
constraintsBuilder.setStart(calendar.timeInMillis)   //   2
calendar.roll(Calendar.YEAR, 1)   //   3
constraintsBuilder.setEnd(calendar.timeInMillis)   // 4
builder.setCalendarConstraints(constraintsBuilder.build())   //  5
val picker: MaterialDatePicker<*> = builder.build()
picker.show(supportFragmentManager, picker.toString())

Here’s what we’re doing in the above code.

  1. Creating a new instance of CalendarConstranints.Builder class. This class used to limit the display range.
  2. Setting out the start date as the current date. Now the Date Picker will use the current month as a start of the year.
  3. Sets the new date to the calendar instance by adding the 1 year. So, that we can restrict user within one month.
  4. Sets the end date.
  5. Finally, build the constraints using a set of parameters we passed to it.

Now we only allow the user to select a date within a year.

Allow Only Valid Days For Material Date Picker

Valid days are like to only allow the user to select a date or range of dates from the DateValidator. As an example let’s say we want our user to only a select date from working days and disable all the weekend days.

val constraintsBuilder = CalendarConstraints.Builder()  
constraintsBuilder.setValidator(WeekDayValidator())  //  1
builder.setCalendarConstraints(constraintsBuilder.build())   
val picker: MaterialDatePicker<*> = builder.build()
picker.show(supportFragmentManager, picker.toString())

The only noticeable thing in the above code is the WeekDayValidator class.

Here is the WeekDayValidator class implementation.

class WeekDayValidator : CalendarConstraints.DateValidator {

    private val utc =
        Calendar.getInstance(TimeZone.getTimeZone("UTC"))
    val CREATOR: Parcelable.Creator<WeekDayValidator?> =
        object : Parcelable.Creator<WeekDayValidator?> {
            override fun createFromParcel(source: Parcel): WeekDayValidator {
                return WeekDayValidator()
            }

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

    override fun writeToParcel(dest: Parcel?, flags: Int) {

    }

    override fun isValid(date: Long): Boolean {
        utc.timeInMillis = date
        val dayOfWeek = utc[Calendar.DAY_OF_WEEK]
        return dayOfWeek != Calendar.SATURDAY && dayOfWeek != Calendar.SUNDAY
    }

    override fun describeContents(): Int {
        return 0
    }
    
    override fun hashCode(): Int {
        val hashedFields = arrayOf<Any>()
        return hashedFields.contentHashCode()
    }
}

You see in the above demo all the Saturday’s and Sunday’s are disabled.

Material Date Picker With Date Range

If we need a MaterialDatePicker where our user can select a range of dates then we can do that like so:

val builder: MaterialDatePicker.Builder<Pair<Long, Long>> =
                MaterialDatePicker.Builder.dateRangePicker()
val picker: MaterialDatePicker<*> = builder.build()
picker.show(supportFragmentManager, picker.toString())

As a result of the above code, we get a date picker like this.

Input Modes

The Google Material Library also allows manual entry using the numbers to input the date for Material Date Picker. Users can input a date or range of dates.

Here are a couple of input modes available.

  • INPUT_MODE_CALENDAR (default)
  • INPUT_MODE_TEXT

So, in order to show input mode for the date picker, we need to set it with the setInputMode method.

val builder: MaterialDatePicker.Builder<Pair<Long, Long>> =
                MaterialDatePicker.Builder.datePicker()
builder.setInputMode(MaterialDatePicker.INPUT_MODE_TEXT)
val picker: MaterialDatePicker<*> = builder.build()
picker.show(supportFragmentManager, picker.toString())

Material Date Picker Click Listener Handling

So, after showing the dialog we need to know what happens when a user interacts with the date picker.

There are three listeners added for Material Date Picker.

  • addOnCancelListener: Called when a user press on outside date picker and dialog gets canceled.
picker.addOnCancelListener {
     toast("dialog canceled")
}
  • addOnNegativeButtonClickListener: Triggers when the dialog negative button clicked.
picker.addOnNegativeButtonClickListener {
     toast("dialog negative button clicked")
}
  • addOnPositiveButtonClickListener: A successful when a user selects the date or date ranges.
picker.addOnPositiveButtonClickListener {
     val (startOfRange, endOfRange) = it   // in case date range operation
     val date = it //  single select date
}

Apply Theming

In last I just wanna show you guys how we can change the Material Date Picker dialog to fullscreen and revert it to normal dialog.

Here are a couple of material themes available.

  • R.attr.materialCalendarTheme (default)
  • R.attr.materialCalendarFullscreenTheme
  private fun resolveOrThrow(context: Context, @AttrRes attributeResId: Int): Int {
        val typedValue = TypedValue()
        if (context.theme.resolveAttribute(attributeResId, typedValue, true)) {
            return typedValue.data
        }
        throw IllegalArgumentException(context.resources.getResourceName(attributeResId))
   }

val fullscreenTheme = resolveOrThrow(getContext(), R.attr.materialCalendarFullscreenTheme)
val builder: MaterialDatePicker.Builder<Pair<Long, Long>> =
                MaterialDatePicker.Builder.datePicker()
builder.setTheme(fullscreenTheme)
val picker: MaterialDatePicker<*> = builder.build()
picker.show(supportFragmentManager, picker.toString())

That’s all guys, thanks for reading this till the end. If you like what you read please share it with the community and don’t forget to hit the ♥️ button below. Please provide feedback if you think this article can be improved.

I also wrote a couple of articles on Material Design Components in case you wanna check out. Here is the link.

Thank you for being here and keep reading…

7 Comments

  1. when i set end date,it is restricting month only not date how can i set max date for material calendar.

    • ahsensaeed067 Reply

      Hey Sarath,
      In order to restrict the user to only select dates, you can set a start and end date with only to select valid days. See section second and third.

      • getting black background in the date picker date selection can i know how to change that to white as you showed in the screenshots.tried in many ways but didn’t get.color Accent gives me date picker header color change only.

        here is my styles

        @color/primary
        @color/colorPrimary
        @color/primary
        @drawable/activated_background
        true
        @android:color/white

  2. hey, can I change “save” button to display something else? For example, “ok” or something.

  3. hi,

    can i know how to change background of the material date picker(styles.xml(color accent gives the change in material header color)).the background which are having dates getting black and text is white.i would like to change my background as white as you showed in screenshot and text as black.can you please let me know about this.

Write A Comment