42

I read the documentation: http://developer.android.com/guide/topics/ui/controls/pickers.html but now in lollipop appears the calendar (it is ok for an event but horrible for set a date of birth, I would a spinner mode.) and I can't remove it! In layout It's easy with this property:

 <DatePicker
 datePickerMode="spinner"...>

but from code of the DatePickerDialog if I try to set

dialogDatePicker.getDatePicker().setSpinnersShown(true);
dialogDatePicker.getDatePicker().setCalendarViewShown(false); 

These properties do not work and the calendar continues to appear!

public static class MyDatePicker extends DialogFragment implements DatePickerDialog.OnDateSetListener {
        int pYear;
        int pDay;
        int pMonth;

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            // Use the current date as the default date in the picker
            final Calendar c = Calendar.getInstance();
            int year = c.get(Calendar.YEAR);
            int month = c.get(Calendar.MONTH);
            int day = c.get(Calendar.DAY_OF_MONTH);
            DatePickerDialog dialogDatePicker = new DatePickerDialog(getActivity(), this, year, month, day);
            dialogDatePicker.getDatePicker().setSpinnersShown(true);
            dialogDatePicker.getDatePicker().setCalendarViewShown(false);
            return dialogDatePicker;
            // Create a new instance of DatePickerDialog and return it
            //return new DatePickerDialog(getActivity(), this, year, month, day);
        }

        public void onDateSet(DatePicker view, int year, int month, int day) {
            pYear = year;
            pDay = day;
            pMonth = month;
        }
    }
Evilripper
  • 1,165
  • 1
  • 15
  • 26

13 Answers13

58

DatePickerDialog uses the dialog theme specified by your activity theme. This is a fully-specified theme, which means you need to re-specify any attributes -- such as the date picker style -- that you've set in your activity theme.

<style name="MyAppTheme" parent="android:Theme.Material">
    <item name="android:dialogTheme">@style/MyDialogTheme</item>
    <item name="android:datePickerStyle">@style/MyDatePicker</item>
</style>

<style name="MyDialogTheme" parent="android:Theme.Material.Dialog">
    <item name="android:datePickerStyle">@style/MyDatePicker</item>
</style>

<style name="MyDatePicker" parent="android:Widget.Material.DatePicker">
    <item name="android:datePickerMode">spinner</item>
</style>

Note: Due to Issue 222208, this will not work in Android N / API 24. It has already been fixed in the platform for the next release. There is no workaround available for API 24 devices.

alanv
  • 23,966
  • 4
  • 93
  • 80
42

Apply the Holo_theme in the code level got worked for me.

new DatePickerDialog(getActivity(),android.R.style.Theme_Holo_Dialog,this, year,month, day);
Gopi Cg
  • 384
  • 3
  • 7
Nithin Raja
  • 1,144
  • 12
  • 11
  • 4
    Great answer! android.R.style.Theme_Holo_Light_Dialog looks much better though – Nativ May 10 '17 at 17:21
  • @WaqasRaja Same issue.. did you find any solution? – iMDroid Jul 17 '17 at 11:43
  • As mentioned in the above comments , It is not working on API 24 , but its working for older API level. Can anybody tell How to make it work on API 24 ? – RavikanthM Sep 04 '17 at 13:45
  • 4
    android.R.style.Theme_Holo_Dialog is deprecated now – Leo DroidCoder Jan 13 '19 at 13:44
  • It still works on API 25 for me. Not sure why API 24 is a one-off issue. In regards to the deprecation, yes it is deprecated, you are not supposed to use Holo themes, but it is highly unlikely they will remove it from the SDK, further it is not like you are using deprecated code, all that style is doing is using `spinner` – androidguy Sep 18 '19 at 21:28
20

I think the best solution to this problem is define a new style in the XML file and then use it programatically in the code.

Though @alanv answer is perfect and will work correctly, the problem with it is that it will be applied for all the Date pickers. Suppose you have one DatePicker where you need to show Calendar view, and another DatePicker where you need to show spinner view, this will not work.

So define a new style in a styles.xml. Create this file in a folder named values-v21 (see naming structure here), since these attributes are introduced post lollipop only. Before lollipop, there was only spinner mode.

 <style name="CustomDatePickerDialogTheme" parent="android:Theme.Material.Light.Dialog">
    <item name="android:datePickerStyle">@style/MyDatePickerStyle</item>
</style>

<style name="MyDatePickerStyle" parent="@android:style/Widget.Material.DatePicker">
    <item name="android:datePickerMode">spinner</item>
</style>

And finally, use it in the code like this

DatePickerDialog datePickerDialog = new DatePickerDialog(getActivity(),
    R.style.CustomDatePickerDialogTheme, this, year, month, day);
return datePickerDialog;
Community
  • 1
  • 1
thedarkpassenger
  • 7,158
  • 3
  • 37
  • 61
  • You should also provide the the corresponding entry in your `style.xml` in the values folder. Otherwise the DatePicker has the wrong styling on pre-Lollipop devices. – OneWorld Dec 03 '19 at 12:58
14

You can use a library to create the old "spinner" style DatePicker which is just three NumberPicker put together:

https://github.com/drawers/SpinnerDatePicker

spinner date picker

First, define a style:

<style name="NumbePickerStyle">
    <item name="android:textSize">22dp</item>
    <item name="android:textColorPrimary">@color/colorAccent</item>
    <item name="android:colorControlNormal" tools:targetApi="lollipop">@color/colorAccent</item>
</style>

Then,

new SpinnerDatePickerDialogBuilder()
        .context(MainActivity.this)
        .callback(MainActivity.this)
        .spinnerTheme(spinnerTheme)
        .year(year)
        .monthOfYear(monthOfYear)
        .dayOfMonth(dayOfMonth)
        .build()
        .show();

Disclaimer: I am the author of this library

David Rawson
  • 20,912
  • 7
  • 88
  • 124
10

Add the attribute calendarViewShown and set it to false:

<DatePicker
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/date_field"
android:calendarViewShown="false"/>
Carlos Espinoza
  • 1,115
  • 11
  • 13
5

This answer is a bit off-topic but provides an alternative approach with the standard DatePicker which can be useful to someone.
It's 2019 now and this issue still persists.

  • android:datePickerMode="spinner" doesn't work at all the APIs
  • Integrating a library for such a simple task (having quite nice material picker) is not what every developer wants.

From another point of view, the widget is quite handy, the problem is that not all the Android users know they can open the year selection section, which makes year selection easy:

enter image description here

This creates not the best UX for some users and they are having hard times with the date of birth selection (some users just swipe calendar until reach the needed year)

I ended up with a workaround solution which lets doing one of the following:

  1. Initially show user year selection view of the DatePicker (image above), after which he navigates to the calendar view
  2. Or show a regular calendar view, with highlighting the "Year button" with the ripple (or in another way, such as Year's background change to make it look like a button).

See the animation below on how different solutions are seen for a user:

enter image description here

Here is what you need:

  1. Show a DatePicker (DatePickerDialog or a DialogFragment which creates it).
  2. Retrieve the "Year" TextView:

    val yearTextview =dialog.findViewById<TextView>(context.resources
    ?.getIdentifier("android:id/date_picker_header_year", null, null)?: -1)
    
  3. Do whatever you want with it, for instance:

    • Perform a click programmatically to select a year section:

    yearTextview?.performClick()

    • Show a ripple effect after showing (with setting yearTextview?.isPressed = true for some period of time)

    • Change it's background etc.

Drawback: if the id will be changed in the next API's - it will require you to change it accordingly

Leo DroidCoder
  • 14,527
  • 4
  • 62
  • 54
  • 2
    This is an excellent approach that doesn't exactly match what the OP wants, but is perhaps the best overall solution. – Tom Jul 22 '19 at 19:39
2

Can you try this

DatePickerDialog dialogDatePicker = new DatePickerDialog(getActivity(), this, year, month, day);
            dialogDatePicker.getDatePicker().setCalendarViewShown(false);
            return dialogDatePicker;

removing

dialogDatePicker.getDatePicker().setSpinnersShown(true);
Fahim
  • 12,198
  • 5
  • 39
  • 57
2

Try this it worked for me, do a custom datelistener:

    @SuppressWarnings("deprecation")
    public void setDate(View view) {
        showDialog(999);
    }

    @SuppressWarnings("deprecation")
    protected Dialog onCreateDialog(int id) {
        // TODO Auto-generated method stub
        if (id == 999) {
            return new DatePickerDialog(this, myDateListener, year, month-1, day);
        }
        return null;
    }
    //THIS
    private DatePickerDialog.OnDateSetListener myDateListener= new DatePickerDialog.OnDateSetListener() {

        @Override
        public void onDateSet(DatePicker arg0, int arg1, int arg2, int arg3) {

            showDate(arg1, arg2+1, arg3);
        }
    };

    private void showDate(int year, int month, int day) {

        //dateView.setText(new StringBuilder().append(day).append("-")
               // .append(month).append("-").append(year));
    }
MarcS
  • 681
  • 5
  • 12
2

All fancy stuff aside, use the DatePickerDialog constructor that takes an "int theme" parameter. Without it, it seems to default to whichever int sets it to CalendarView mode. With small integers (0, 1, 2, 3...) it will give you a spinner (at least in my API 19 app run on an emulator). Basically, try new DatePickerDialog( getContext(), 0, this, year, month, day ) Notice the 0 (or 1, or 2, etc) there

Caution: I'm not sure if there's a list somewhere of static theme fields, and using a hardcoded "0" instead of "Theme.HOLO_LIGHT" or whatever could make a difference on different devices, but it gets the job done somehow.

plainOldNerd
  • 305
  • 2
  • 8
2

Step-1: Create spinner/calendar date picker layout

.../main/res/layout/spinner_date_picker_layout.xml

    <?xml version="1.0" encoding="utf-8"?>
    <DatePicker xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/datePicker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:datePickerMode="spinner"
        android:calendarViewShown="false" />

.../main/res/layout/calendar_date_picker_layout.xml

    <?xml version="1.0" encoding="utf-8"?>
    <DatePicker xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/datePicker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:datePickerMode="calendar" />

Step-2: Set clickable behavior on TextView for showing Date Dialog.

.../main/res/layout/activity_layout.xml

    <TextView
        android:id="@+id/dateText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:clickable="true"
        android:text="Date"
        android:onClick="@{() -> viewModel.onClickDate()}"></TextView>

Step-3: Show Dialog on onClickDate

override fun onClickDate() {
        showDialogForDate()
}

Step-4: Set DatePicker Layout into Dialog View.

private fun showDialogForDate() {

    //Set spinner/calendar date picker layout
    val spinnerDatePicker = layoutInflater.inflate(R.layout.spinner_date_picker_layout, null)

    // On click listener for dialog buttons
    val dialogClickListener = DialogInterface.OnClickListener { _, which ->
        when (which) {
            DialogInterface.BUTTON_POSITIVE -> {
                activity!!.dateText.text = spinnerDatePicker.datePicker.dayOfMonth.toString() + "/" + (spinnerDatePicker.datePicker.month + 1) + "/" + spinnerDatePicker.datePicker.year
            }
            DialogInterface.BUTTON_NEGATIVE -> {

            }
        }
    }

    val builder = AlertDialog.Builder(context!!)
    builder.setTitle(resources.getString(R.string.dialog_title))
        .setView(spinnerDatePicker)
        .setPositiveButton("Ok", dialogClickListener)
        .setNegativeButton("Cancel", dialogClickListener)
        .create()
        .show()
}
B. Go
  • 1,436
  • 4
  • 15
  • 22
2
<DatePicker
    android:id="@+id/datePicker"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:calendarViewShown="false"
    android:datePickerMode="spinner"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    android:theme="@style/NumberPickerStyle"
    tools:targetApi="lollipop" />

Inflate this in a dialog and you are done. Although the android:datePickerMode may show you API 21 and high warning, it should work in previous versions of android as well, because the DatePicker style itself is an old style. I tested this implementation in API 16 and above and faced no issues.

Spinner Date Picker Dialog

Code:

private fun showOldDatePickerDialog() {
    with(View.inflate(this, R.layout.old_style_date_picker, null)){
        AlertDialog.Builder(context)
                .setView(this)
                .setPositiveButton("Ok") { _, _ ->
                    Log.d("DatePicker","${this.datePicker.month.plus(1)} : ${this.datePicker.dayOfMonth} : ${this.datePicker.year}")
                }.create().also { it.show() }
    }
}

To change the text size add this to your styles.

<style name="NumberPickerStyle">
    <item name="android:textSize">21sp</item>
</style>
Sai
  • 15,188
  • 20
  • 81
  • 121
1

DatePicker methods related to showing spinner and/or calendar view are deprecated from API level 24. Method setSpinnersShown(boolean shown) and setCalendarViewShown(boolean shown) are deprecated because calendar mode material style doesn't support the feature.

If you want to use material style in spinner mode, use DatePicker widget.

Apply below style to your date picker xml element to get material spinner. For more information on date picker and styles see http://www.zoftino.com/android-datepicker-example .

<style name="MyDatePickerSpinnerStyle" parent="@android:style/Widget.Material.DatePicker">
    <item name="android:datePickerMode">spinner</item>
    <item name="android:calendarViewShown">false</item>
    <item name="colorControlNormal">#d50000</item>
</style>
Arnav Rao
  • 6,692
  • 2
  • 34
  • 31
  • Not sure if its changed since you posted this, but you can just do android:calendarViewShown="false" in the xml file where you declared the DatePicker right along side the DatePickers other properties – lbenedetto Apr 14 '18 at 02:36
0
<DatePicker
    android:calendarViewShown="false"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:datePickerMode="spinner"/>

calendatViewShown will remove the calendar view and dataPickerMode has to be set to the spinner to show the Spinner view that you need.

Gaurav Rai
  • 370
  • 1
  • 3
  • 16