Domanda

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.

È stato utile?

Soluzione

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);
        }
    }
}

Altri suggerimenti

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;
}

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

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>

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)));

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) {
    }
}

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.

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;
                }
            }
        }
    }   
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top