Android divider color DatePicker dialog
Asked Answered
R

8

13

I'm trying to change color of the blue dividers for a DatePicker in a dialog. This is just a normal DialogFragment with a DatePicker and a ButtonBar.

Does anyone know to change these dividers, or if it's even possible without replacing the entire DatePicker with a custom one?

Screenshot DatePicker

Mini rant

Now I've seen too many answers suggesting the following code:

<style name="datePickerTheme" parent="@android:style/Widget.DeviceDefault.DatePicker">
    <item name="android:divider">**your @drawable/ or @color/ here**</item>
</style>

Which simply does not work. Have you guys tried this before suggesting this code? It should work perfectly, but it does not seem to work with the DatePicker.

Rep answered 10/9, 2013 at 8:46 Comment(0)
S
24

The following approach worked for me.This sets divider colours for all fields (also for am/pm)

 private void applyStyLing(TimePickerDialog timePickerDialog){
    Resources system = Resources.getSystem();
    int hourNumberPickerId = system.getIdentifier("hour", "id", "android");
    int minuteNumberPickerId = system.getIdentifier("minute", "id", "android");
    int ampmNumberPickerId = system.getIdentifier("amPm", "id", "android");

    NumberPicker hourNumberPicker = (NumberPicker) timePickerDialog.findViewById(hourNumberPickerId);
    NumberPicker minuteNumberPicker = (NumberPicker) timePickerDialog.findViewById(minuteNumberPickerId);
    NumberPicker ampmNumberPicker = (NumberPicker) timePickerDialog.findViewById(ampmNumberPickerId);

   setNumberPickerDividerColour(hourNumberPicker);
   setNumberPickerDividerColour(minuteNumberPicker);
   setNumberPickerDividerColour(ampmNumberPicker);
}

private void setNumberPickerDividerColour(NumberPicker number_picker){
    final int count = number_picker.getChildCount();

    for(int i = 0; i < count; i++){

        try{
            Field dividerField = number_picker.getClass().getDeclaredField("mSelectionDivider");
            dividerField.setAccessible(true);
                ColorDrawable colorDrawable = new ColorDrawable(mContext.getResources().getColor(R.color
                        .interactive_color));
            dividerField.set(number_picker,colorDrawable);

            number_picker.invalidate();
        }
        catch(NoSuchFieldException e){
            Log.w("setNumberPickerTxtClr", e);
        }
        catch(IllegalAccessException e){
            Log.w("setNumberPickerTxtClr", e);
        }
        catch(IllegalArgumentException e){
            Log.w("setNumberPickerTxtClr", e);
        }
    }
}
Salvidor answered 26/4, 2016 at 22:1 Comment(4)
This solution works even if you pass TimePicker object to applyStyLing() it will find the children views as well. The solution is a little bit long and fine for now, at least is working , and need some more upvote +1 :)Lui
Though not the best solution, but yes it works like a magic. Deserves +1. Thanks @Ajit....yes android styles are broken for pre-lollipop and lollipop devicesColza
This solution works great on multiple devices(4-5 different OS and brands), except Nexus 5x (7.0). The timePickerDialog.findViewById(hourNumberPickerId) returns null. Anybody else encountered this ?Farahfarand
Will not work on 28+ API. developer.android.com/about/versions/10/non-sdk-q?authuser=1Inheritor
C
17

I solved this by doing this:

I changed the DatePicker divider with reflection by finding the "mSelectionDivider". Then I had problems with the Title divider looking stupid, so i added a textview above the LinearLayout containing the 3 datepickers and used newFragment.setTitle(""); to remove the original one.

Example for divider drawable: Credits to the guy who made this! :) http://ge.tt/8wK7TZ71/v/0?c

Result picture <-My result

Example:

    public DatePickerDialog makeDatePicker(OnDateSetListener listener, Calendar cal) {
    Calendar c;
    if (cal == null) {
        c = Calendar.getInstance();
    } else {
        c = cal;
    }
    int year = c.get(Calendar.YEAR);
    int month = c.get(Calendar.MONTH);
    int day = c.get(Calendar.DAY_OF_MONTH);
    DatePickerDialog newFragment = new DatePickerDialog(this, listener, year, month, day);

    // removes the original topbar:
    newFragment.setTitle(""); 

    // Divider changing:
    DatePicker dpView = newFragment.getDatePicker(); 
    LinearLayout llFirst = (LinearLayout) dpView.getChildAt(0);
    LinearLayout llSecond = (LinearLayout) llFirst.getChildAt(0);
    for (int i = 0; i < llSecond.getChildCount(); i++) {
        NumberPicker picker = (NumberPicker) llSecond.getChildAt(i); // Numberpickers in llSecond
        // reflection - picker.setDividerDrawable(divider); << didn't seem to work.
        Field[] pickerFields = NumberPicker.class.getDeclaredFields();
        for (Field pf : pickerFields) {
            if (pf.getName().equals("mSelectionDivider")) {
                pf.setAccessible(true);
                try {
                    pf.set(picker, getResources().getDrawable(R.drawable.np_numberpicker_selection_divider_orange));
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (NotFoundException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }
    // New top:
    int titleHeight = 90;
    // Container:
    LinearLayout llTitleBar = new LinearLayout(this);
    llTitleBar.setOrientation(LinearLayout.VERTICAL);
    llTitleBar.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, titleHeight));

    // TextView Title:
    TextView tvTitle = new TextView(this);
    tvTitle.setText("Select a date");
    tvTitle.setGravity(Gravity.CENTER);
    tvTitle.setPadding(10, 10, 10, 10);
    tvTitle.setTextSize(24);
    tvTitle.setTextColor(Color.BLACK);
    tvTitle.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, titleHeight-2));
    llTitleBar.addView(tvTitle);

    // View line:
    View vTitleDivider = new View(this);
    vTitleDivider.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 2));
    vTitleDivider.setBackgroundColor(getResources().getColor(R.color.crumblrOrange));
    llTitleBar.addView(vTitleDivider);

    dpView.addView(llTitleBar);
    FrameLayout.LayoutParams lp = (android.widget.FrameLayout.LayoutParams) llFirst.getLayoutParams();
    lp.setMargins(0, titleHeight, 0, 0);
    return newFragment;
}
Chavannes answered 7/12, 2013 at 12:24 Comment(1)
Will not work on 28+ API. developer.android.com/about/versions/10/non-sdk-q?authuser=1Inheritor
M
15

I based this code on Ajit's answer, but I tweaked it for DatePicker rather than TimePicker. Moreover, I added a null check just to stay on the safe side:

public static void colorizeDatePicker(DatePicker datePicker) {
    Resources system = Resources.getSystem();
    int dayId = system.getIdentifier("day", "id", "android");
    int monthId = system.getIdentifier("month", "id", "android");
    int yearId = system.getIdentifier("year", "id", "android");

    NumberPicker dayPicker = (NumberPicker) datePicker.findViewById(dayId);
    NumberPicker monthPicker = (NumberPicker) datePicker.findViewById(monthId);
    NumberPicker yearPicker = (NumberPicker) datePicker.findViewById(yearId);

    setDividerColor(dayPicker);
    setDividerColor(monthPicker);
    setDividerColor(yearPicker);
}

private static void setDividerColor(NumberPicker picker) {
    if (picker == null)
        return;

    final int count = picker.getChildCount();
    for (int i = 0; i < count; i++) {
        try {
            Field dividerField = picker.getClass().getDeclaredField("mSelectionDivider");
            dividerField.setAccessible(true);
            ColorDrawable colorDrawable = new ColorDrawable(picker.getResources().getColor(R.color.colorAccent));
            dividerField.set(picker, colorDrawable);
            picker.invalidate();
        } catch (Exception e) {
            Log.w("setDividerColor", e);
        }
    }
}

Output

colored dividers

Microbiology answered 25/5, 2016 at 13:48 Comment(1)
Will not work on 28+ API. developer.android.com/about/versions/10/non-sdk-q?authuser=1Inheritor
E
13

This fixed my problem adding below line of code to App theme style.

<item name="colorControlNormal">@color/colorAccent</item>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
  <item name="colorControlNormal">@color/blue</item> 
</style>
Eurasian answered 30/11, 2016 at 16:39 Comment(3)
nice and clean.ThanksNotability
Works for me!! Thanks!!Jeer
The approach is not worked on API Level 21 Emulator. but on API Level 23 Emulator and on API Level 29 Device(Essential Phone) is worked fine!! In layout xml: <NumberPicker app:theme="@style/AppTheme.NumberPicker" /> in styles.xml:<style name="AppTheme.NumberPicker"><item name="colorControlNormal">@color/themeColor</item></style>Pavlodar
A
4

Take into account:

You don't need a new R.drawable.divider

you can write:

 pf.set(number_picker, new ColorDrawable(getResources().getColor(R.color.red)));
Avowed answered 18/2, 2015 at 3:21 Comment(1)
Will not work on 28+ API. developer.android.com/about/versions/10/non-sdk-q?authuser=1Inheritor
M
2

This version is adjusted for specific use with DatePicker. While Andrea Lazzarotto's version works fine, it uses an unnecessary loop which leads to multiple appliance of the color change. Besides minor code improvements, my version uses the app theme's primary color to match the divider color (see How can I get the primary color from my app theme?). Tested with Android 6.0 and 8.0:

private void colorizeDatePicker(final DatePicker datePicker) {
    final Resources system = Resources.getSystem();
    final String defType = "id";
    final String defPackage = "android";

    final int dayId = system.getIdentifier("day", defType, defPackage);
    final int monthId = system.getIdentifier("month", defType, defPackage);
    final int yearId = system.getIdentifier("year", defType, defPackage);

    final NumberPicker dayPicker = (NumberPicker) datePicker.findViewById(dayId);
    final NumberPicker monthPicker = (NumberPicker) datePicker.findViewById(monthId);
    final NumberPicker yearPicker = (NumberPicker) datePicker.findViewById(yearId);

    setDividerColor(dayPicker);
    setDividerColor(monthPicker);
    setDividerColor(yearPicker);
}

private void setDividerColor(final NumberPicker picker) {
    if (picker == null) {
        return;
    }

    try {
        final Field dividerField = picker.getClass().getDeclaredField("mSelectionDivider");
        dividerField.setAccessible(true);

        final TypedValue outValue = new TypedValue();
        getContext().getTheme().resolveAttribute(R.attr.colorPrimary, outValue, true);
        final int dividerColor = outValue.data;

        dividerField.set(picker, new ColorDrawable(dividerColor));
        picker.invalidate();
    } catch (Exception e) {
    }
}
Mcclean answered 1/8, 2017 at 13:33 Comment(2)
this should be the accepted answer. Thanks @Michael TrogerBerl
Will not work on 28+ API. developer.android.com/about/versions/10/non-sdk-q?authuser=1Inheritor
G
1

Yes of course you can. You can use these attributes for instance:

<NumberPicker
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            selectionDivider="@color/black" //The divider for making the selection area
            selectionDividerHeight="1px"//The height of the selection divider
            selectionDividersDistance="3dp"//The distance between the two selection dividers
            internalLayout="@layout/something"//The layout of the number picker.
            internalMaxHeight="5dp"//The max height of the NumberPicker (also check other variations)
            internalMinWidth="5dp" // The max width of the NumberPicker (also check other variations)
            virtualButtonPressedDrawable="@drawable/something"//The drawable for pressed virtual (increment/decrement) buttons.
            />

Update :

You can use this custom datepicker. It's highly customizable and backward competiable. It basically uses numberpicker and you can set divider using attributes above.

Gentian answered 10/9, 2013 at 10:48 Comment(3)
This is code for a NumberPicker, the DatePicker does not seem to have a selectionDivider attribute? edit: ...This gives errors as well for the NumberPicker?Rep
The android:selectionDivider seems to be a private attribute for the Number- and DatePicker, I cannot alter it.Rep
I have updated my answer. Could you check if it works for you?Gentian
D
1

Thanks Mvj for solving the problem! Just thought I'd also show my implementation of your solution on the timepickers' dividers.

    TimePickerDialog ptd = new TimePickerDialog(getActivity(), R.style.PickerStyler, this, hour, minute,DateFormat.is24HourFormat(getActivity()));
    ptd.setTitle("");

    //Needs to be try catched
    Field mTimePickerField = ptd.getClass().getDeclaredField("mTimePicker");
    mTimePickerField.setAccessible(true);
    TimePicker mTimePickerInstance = (TimePicker) mTimePickerField.get(ptd);    

    LinearLayout llFirst = (LinearLayout) mTimePickerInstance.getChildAt(0);
    LinearLayout llSecond = (LinearLayout) llFirst.getChildAt(0);
    boolean continiue = false;
    NumberPicker picker = null;
    for (int i = 0; i < llSecond.getChildCount(); i++) {            
        continiue = true;
        try{picker = (NumberPicker) llSecond.getChildAt(i);
            }catch(Exception e){continiue = false;}

        if(continiue){
            Field[] pickerFields = NumberPicker.class.getDeclaredFields();
            for (Field pf : pickerFields) {
                if (pf.getName().equals("mSelectionDivider")) {
                    pf.setAccessible(true);
                    try {
                        pf.set(picker, getResources().getDrawable(R.drawable.divider));
                    } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                    } catch (NotFoundException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    break;
                }
            }
        }
    }   
Dissimilarity answered 27/5, 2014 at 8:2 Comment(5)
It is not setting the am/pm field's dividers, any idea why? Only first 2 fields' dividers are being set with a different color.Salvidor
Actually no, sorry. This was made with KitKat as target. What's your os version? maybe this is obsoleteDissimilarity
maybe the pickerField has another name than mSelectionDivider.Dissimilarity
please see the solution I posted below. actually the third field (am/pm) is not a time picker but it is a NumberPicker.CustomEditText, hence the above approach which is type casting to timePicker was failing, kindly see the other approach below and let me know if you find it useful. It works in all versions.Salvidor
Will not work on 28+ API. developer.android.com/about/versions/10/non-sdk-q?authuser=1Inheritor

© 2022 - 2024 — McMap. All rights reserved.