Changing NumberPicker divider color
Asked Answered
C

13

51

On recent android versions, number pickers use a blue divider when drawn (cf. image below).

enter image description here

I would like to change this color. Is there a working solution? or perhaps a library that package an updated version of NumberPicker that allows customizing the divider color?

I have tried android-numberpicker but I get an error (see below) at runtime due to some code from the library that tries to access to a resource id that does not exist.

android.content.res.Resources$NotFoundException: Resource ID #0x0
        at android.content.res.Resources.getValue(Resources.java:1123)
        at android.content.res.Resources.loadXmlResourceParser(Resources.java:2309)
        at android.content.res.Resources.getLayout(Resources.java:939)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:395)
        at net.simonvt.numberpicker.NumberPicker.<init>(NumberPicker.java:635)
        at net.simonvt.numberpicker.NumberPicker.<init>(NumberPicker.java:560)
        at net.simonvt.numberpicker.NumberPicker.<init>(NumberPicker.java:550)
Cowes answered 15/6, 2014 at 19:56 Comment(2)
Does this answer your question?: #18805262Alewife
No, it's not working. First answer that aims to create a custom style is not working because symbol '@style/Holo.NumberPicker' cannot be resolved. For the second answer, the result is the same: calling set(numberPicker, color) on field mSelectionDivider retrieved by reflection has no effect.Cowes
T
30

Based on this (https://mcmap.net/q/354455/-android-how-to-change-the-color-of-the-datepicker-divider although it's about DatePicker) there are several ways:

  1. Write your own NumberPicker without mSelectionDivider and its affiliates or use backported by Vikram. In last case:
  2. download from lib from github
  3. change drawable in res/drawable-xxx/np_numberpicker_selection_divider.9.png:
  • to transparent (or whatever) .9.png * create np_numberpicker_selection_divider.xml shape line resource in res/drawable (with 0dp height or transparent color).
  1. OR remove if (mSelectionDivider != null) branch from onDraw(Canvas) method in NumberPicker.java like here

  2. Use reflection to access private final field mSelectionDivider (details: https://github.com/android/platform_frameworks_base/blob/master/core/java/android/widget/NumberPicker.java) - e.g. see modification here. I used reflection but it's not the best solution.

  3. Use theming to override the number picker's divider color in API 21+: ?attr/colorControlNormal determines the color of the divider in material number picker, so changing this color in your widget's theme will do the trick, e.g. for DatePicker:

    <style name="MyAppTheme.NumberPicker" parent=" MyAppTheme">
        <item name="android:colorControlNormal"> ?colorAccent </item>
    </style>

and in the widget:

 <DatePicker
        android:id="@+id/question_date"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" 
        android:calendarViewShown="false"
        android:datePickerMode="spinner"
        android:gravity="center"
        android:theme="@style/MyAppTheme.NumberPicker" />
Towel answered 18/6, 2014 at 21:42 Comment(1)
Thank you for your help. Solution 2 works perfectly but I failed to make solution 1 work. For this last, resource id associated to variable DEFAULT_LAYOUT_RESOURCE_ID in NumberPicker.java seems to be no longer valid. Last but not least, my goal was to change color to a custom one and not to hide dividers. To achieve this goal I haven't set mSelectionDivider to null but equals to a drawable which is a simple nine patch PNG loaded with getResources().getDrawable(R.drawable.np_numberpicker_selection_divider)Cowes
P
74

This worked for me without using the reflection.

my_layout.xml

<NumberPicker
   ...
   android:theme="@style/DefaultNumberPickerTheme" />

Styles.xml (AppTheme is my app theme in the app)

<style name="DefaultNumberPickerTheme" parent="AppTheme">
        <item name="colorControlNormal">@color/dividerColor</item>
</style>
Phila answered 15/5, 2017 at 17:20 Comment(3)
Just a friendly reminder. 'colorControlNormal', only works for API 21 and above.Janey
please suggest an alternative to 'colorControlNormal' if one existsWentzel
Just want to point out that using colorControlNormal didn't work for me and I had to explicitly add the android: prefix, like so <item name="android:colorControlNormal">#ffffff</item>Anta
A
61

If you want simply to change the color (based on stannums answer):

private void setDividerColor(NumberPicker picker, int color) {

    java.lang.reflect.Field[] pickerFields = NumberPicker.class.getDeclaredFields();
    for (java.lang.reflect.Field pf : pickerFields) {
        if (pf.getName().equals("mSelectionDivider")) {
            pf.setAccessible(true);
            try {
                ColorDrawable colorDrawable = new ColorDrawable(color);
                pf.set(picker, colorDrawable);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (Resources.NotFoundException e) {
                e.printStackTrace();
            }
            catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            break;
        }
    }
}

And after that

setDividerColor(mNumberPicker, Color.GREEN);
Aubergine answered 8/4, 2015 at 14:19 Comment(4)
Nice change. One thing I noticed is to be sure to use 'newColorDrawable(ctx.getResources().getColor(R.color.whatevercolor))' instead of 'new ColorDrawable(R.color.whatevercolor)'Rebekahrebekkah
I really think, that it should mark as a try answer! It is really simple and work!Randi
It might be better: ColorDrawable colorDrawable = new ColorDrawable(ContextCompat.getColor(getContext(), R.color.primaryColor));Unveiling
Thanks mate! I translated this into a Kotlin Extension and its working perfectly.Clay
T
30

Based on this (https://mcmap.net/q/354455/-android-how-to-change-the-color-of-the-datepicker-divider although it's about DatePicker) there are several ways:

  1. Write your own NumberPicker without mSelectionDivider and its affiliates or use backported by Vikram. In last case:
  2. download from lib from github
  3. change drawable in res/drawable-xxx/np_numberpicker_selection_divider.9.png:
  • to transparent (or whatever) .9.png * create np_numberpicker_selection_divider.xml shape line resource in res/drawable (with 0dp height or transparent color).
  1. OR remove if (mSelectionDivider != null) branch from onDraw(Canvas) method in NumberPicker.java like here

  2. Use reflection to access private final field mSelectionDivider (details: https://github.com/android/platform_frameworks_base/blob/master/core/java/android/widget/NumberPicker.java) - e.g. see modification here. I used reflection but it's not the best solution.

  3. Use theming to override the number picker's divider color in API 21+: ?attr/colorControlNormal determines the color of the divider in material number picker, so changing this color in your widget's theme will do the trick, e.g. for DatePicker:

    <style name="MyAppTheme.NumberPicker" parent=" MyAppTheme">
        <item name="android:colorControlNormal"> ?colorAccent </item>
    </style>

and in the widget:

 <DatePicker
        android:id="@+id/question_date"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" 
        android:calendarViewShown="false"
        android:datePickerMode="spinner"
        android:gravity="center"
        android:theme="@style/MyAppTheme.NumberPicker" />
Towel answered 18/6, 2014 at 21:42 Comment(1)
Thank you for your help. Solution 2 works perfectly but I failed to make solution 1 work. For this last, resource id associated to variable DEFAULT_LAYOUT_RESOURCE_ID in NumberPicker.java seems to be no longer valid. Last but not least, my goal was to change color to a custom one and not to hide dividers. To achieve this goal I haven't set mSelectionDivider to null but equals to a drawable which is a simple nine patch PNG loaded with getResources().getDrawable(R.drawable.np_numberpicker_selection_divider)Cowes
O
15

I'm use workaround Java method:

  private void setDividerColor (NumberPicker picker) {   

        java.lang.reflect.Field[] pickerFields = NumberPicker.class.getDeclaredFields();
        for (java.lang.reflect.Field pf : pickerFields) {
            if (pf.getName().equals("mSelectionDivider")) {
                pf.setAccessible(true);
                try {
                    //pf.set(picker, getResources().getColor(R.color.my_orange));
                    //Log.v(TAG,"here");
                    pf.set(picker, getResources().getDrawable(R.drawable.dot_orange));
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (NotFoundException e) {
                    e.printStackTrace();
                } 
                catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
        //}
     }

or Kotlin method:

private fun NumberPicker.setDividerColor(color: Int) {
    val dividerField = NumberPicker::class.java.declaredFields.firstOrNull { it.name == "mSelectionDivider" } ?: return
    try {
       dividerField.isAccessible = true
       dividerField.set(this,getResources().getDrawable(R.drawable.dot_orange))
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

And apply its

  setDividerColor(yourNumberPicker); // for java method
  yourNumberPicker.setDividerColor(Color.RED) // for kotlin method
Obediah answered 30/12, 2014 at 10:49 Comment(0)
A
3

Actually you can change the color of divider writing a custom theme.

As an example add this to your themes.xml

<style name="NumberPickerTheme" parent="Theme.AppCompat.Light">
        <item name="colorAccent">@android:color/white</item>
        
        <!-- Edit this colorControlNormal value as you need -->
        <item name="colorControlNormal">@android:color/holo_green_dark</item>
        
        <item name="android:textColorPrimary">@android:color/black</item>
        <item name="android:background">@android:color/white</item>
        <item name="android:textSize">30sp</item>
    </style>

And Add this theme to your Numberpicker

<NumberPicker
        android:id="@+id/index_picker1"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:theme="@style/NumberPickerTheme"
         />

If you want to get rid of dividers just use

<item name="colorControlNormal">@android:color/transparent</item>
Autointoxication answered 15/6, 2021 at 5:47 Comment(0)
T
2

You can use reflection to do the trick. Here is my solution

public class ColorChangableNumberPicker extends NumberPicker {

    public ColorChangableNumberPicker(Context context) {
        super(context);
        init();
    }

    public ColorChangableNumberPicker(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ColorChangableNumberPicker(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public ColorChangableNumberPicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {
        setDividerColor(Color.RED);
    }


    public void setDividerColor(@ColorInt int color) {
        try {
            Field fDividerDrawable = NumberPicker.class.getDeclaredField("mSelectionDivider");
            fDividerDrawable.setAccessible(true);
            Drawable d = (Drawable) fDividerDrawable.get(this);
            d.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
            d.invalidateSelf();
            postInvalidate(); // Drawable is dirty
        }
        catch (Exception e) {

        }
    }
}
Thyestes answered 24/12, 2015 at 8:39 Comment(1)
I think this is the best ansewr. Also I think this is too mucho for just customizing a single line... But that's system fault. You helped me a lot. ThanksUnfasten
S
2

I'm fairly new to Android so bear in mind that this solution may not be a good practice, but I found a (hacky) way to get this effect using only XML / WITHOUT reflection.

I was able to 'change' the colors of the dividers on my NumberPickers within a LinearLayout by adding 2 thin, horizontal views to the ViewGroup, and giving them negative layout margins and my desired color for their backgrounds:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_gravity="center_horizontal"
    android:gravity="center"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    >
    <NumberPicker
        android:layout_width="70dip"
        android:layout_height="wrap_content"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:layout_gravity="center"
        android:layout_margin="5dp"
        />

    <View
        android:layout_height="2dp"
        android:layout_width="70dp"
        android:background="@color/myColor"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="-75dp"
        android:layout_marginBottom="-25dp">

    </View>

    <View
        android:layout_height="2dp"
        android:layout_width="70dp"
        android:background="@color/myColor"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="-70dp"
        android:layout_marginBottom="25dp">

    </View>

</LinearLayout>

Admittedly, I'm not actually changing the color, but adding new lines with my desired color on top of the built-in dividers. Hopefully this helps someone anyway!

You may have to play with the margins, but these settings were perfect for my custom dialog.

Storehouse answered 27/4, 2016 at 1:37 Comment(1)
sorry this is not a valid solution, to play with margin and elevation or what ever, to hide elements in back of an other view :)Fula
F
1

I use the below code to change the divider, not directly the color, but you can do that with a png like this.

This solution that I bring you comes from here, but my code is a easy simplification to change the divider and that's it.

    // change divider
    java.lang.reflect.Field[] pickerFields = NumberPicker.class
            .getDeclaredFields();
    for (java.lang.reflect.Field pf : pickerFields) {
        if (pf.getName().equals("mSelectionDivider")) {
            pf.setAccessible(true);
            try {
                pf.set(spindle, getResources().getDrawable(R.drawable.np_numberpicker_selection_divider_green));
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (NotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            break;
        }
    }
Fetal answered 5/9, 2014 at 6:38 Comment(0)
W
1

It's easy with my library (I rolled my own NumberPicker too).

<com.github.tomeees.scrollpicker.ScrollPicker
    ...
    app:selectorColor="..."
    />
Warhol answered 22/9, 2018 at 9:15 Comment(1)
com.github.tomeees.scrollpicker.ScrollPicker with its app:selectorColor works well, thank you for making Tamás SajtiVashtee
J
0

using this code for evry thing u want do with divider

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;
                }
            }
Juvenile answered 10/6, 2015 at 20:34 Comment(0)
F
0

It's better to store a private field if you are going to change divider color in future. Like this:

@Nullable private Field dividerField;

public void setDivider(@Nullable Drawable divider) {
    try {
        if (dividerField == null) {
            dividerField = NumberPicker.class.getDeclaredField("mSelectionDivider");
            dividerField.setAccessible(true);
        }

        dividerField.set(this, divider);
    } catch (Exception ignore) {}
}
Fears answered 9/8, 2017 at 15:35 Comment(0)
W
0

Kotlin

You can change divider number in this way without version control. This example set transparent color:

private fun setDividerColor(picker: NumberPicker) {
    val dividerField = NumberPicker::class.java.declaredFields.firstOrNull { it.name == "mSelectionDivider" } ?: return
    try {
        val colorDrawable = ColorDrawable(android.graphics.Color.TRANSPARENT)
        dividerField.isAccessible = true
        dividerField.set(picker, colorDrawable)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}
Weyermann answered 26/11, 2021 at 18:48 Comment(0)
U
-5

simplest way is to add this attribute in you NumberPicker selector in xml

android:selectionDivider="@colors/your_color"
Ubiquitous answered 1/3, 2016 at 14:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.