Change the text color of NumberPicker
Asked Answered
T

11

63

I've looked at most all of the threads on this and none provided an answer that works. Styling the NumberPicker does not work (as per this thread: NumberPicker textColour)

Setting the style attribute on the numberPicker to a style that has a color item does not have any effect either. Nor does setting the textColor attribute on the numberPicker XML do anything.

Closest I've got to this is using the numberPicker to cast its getChildAt() to an EditText and then do setColor() on that EditText, but that only changes the color of the child once upon initialization and then every time it is selected from thereon; not what I am looking for either.

Any help? Thanks

Towill answered 9/4, 2014 at 12:9 Comment(0)
G
108

The solution I tried and worked for me is:

In styles.xml add:

<style name="AppTheme.Picker" parent="Theme.AppCompat.Light.NoActionBar" >
    <item name="android:textColorPrimary">@android:color/black</item>
</style>

Then use it like this inside your layout:

  <NumberPicker
    android:id="@+id/dialogPicker"
    android:theme="@style/AppTheme.Picker"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="15dp" />
Gur answered 9/2, 2016 at 9:4 Comment(6)
This is the simplest and best answer overall. +1Jacquerie
Definately the simplest solution! This is also easy to combine with my custom numberpicker, for which used the theme @android:style/Theme.Dialog to show + and - buttons instead of the slider effect. Now I simply defined the parent as my previous theme (instead of Theme.AppCompat.Light.NoActionBar), and it magically works combined.Mal
This is the best answer. I wish I could up-vote more then +1.Clisthenes
@Gur do you know the property for changing the selection color?Compromise
This answer changes color of all fields of number picker, I mean color of unselected fields will change, too. But what if I want to change just selected field?!Ez
Maybe a bit delayed but if anyone can't find the styles.xml: The styles got migrated into values\themes.xml (with optional themes for day and night).Glomma
H
74

This code should solve your problem. The problem you are experiencing is because during the construction of NumberPicker it captures the EditText textColor and assigns to to a paint so it can draw the numbers above and below the edit text with the same color.

import java.lang.reflect.Field;

public static void setNumberPickerTextColor(NumberPicker numberPicker, int color)
{

    try{
        Field selectorWheelPaintField = numberPicker.getClass()
            .getDeclaredField("mSelectorWheelPaint");
        selectorWheelPaintField.setAccessible(true);
        ((Paint)selectorWheelPaintField.get(numberPicker)).setColor(color);
    }
    catch(NoSuchFieldException e){
        Log.w("setNumberPickerTextColor", e);
    }
    catch(IllegalAccessException e){
        Log.w("setNumberPickerTextColor", e);
    }
    catch(IllegalArgumentException e){
        Log.w("setNumberPickerTextColor", e);
    }

    final int count = numberPicker.getChildCount();
    for(int i = 0; i < count; i++){
        View child = numberPicker.getChildAt(i);
        if(child instanceof EditText)
            ((EditText)child).setTextColor(color);
    }
    numberPicker.invalidate();  
}
Hartley answered 9/4, 2014 at 12:14 Comment(16)
This worked! even with net.simonvt.numberpicker ! It made me crazy that no matter what style I specified, I kept ending up with black text! (black text on black background = useless)Lucknow
Worked for me. You saved me from jumping off my apartment.Frey
All you need to do is override textColorPrimary in your theme. Calling on Reflection API is unnecessary in this case.Chazan
Agreed. However it must be said that this also changes the text color in your entire app and not just the date time picker which may not suite. The question is specific to NumberPicker.Hartley
@Vikram, to be honest all it should have required is android:textColor="@android:color/white"Lucknow
@Hartley For some reason I missed your reply! I guess you forgot to add (at)Vikram to your comment. You said: ..this also changes the text color in your entire app... Well, we can use ContextThemeWrapper to create the LayoutInflater that inflates the date/time/numberpicker. This way, our overridden textColorPrimary affects only the picker, leaving everything else intact. BUT, I do realize that your solution is alright too. I read this somewhere: Reflection is the ability to make modifications at runtime by making use of introspection. So, your usage of reflection is well justified.Chazan
@SomeoneSomewhere Eccentricities of the little green robot.Chazan
I don't like to downvote, and this answer shows good effort, and works, but it is so much worse than @Vikram's answer below that I am downvoting, because I think the community will be better served by Vikram's answer.Betulaceous
Awesome! great solution!Haines
If there is a user interaction, the color changes to the default one. @HartleyMancunian
@SomeoneSomewhere tried to implement the above code but it is not working for me can you please tell me Where I did the mistake #50259039Tomfool
are you getting a "NoSuchFieldException"? Since this code snippet is a while old, I presume that Google has changed the layout and changed the name of the field. It might be better to give Vikram's answer a go, see https://mcmap.net/q/301312/-change-the-text-color-of-numberpickerLucknow
I don't believe this is the best answer. I believe the best answer now is by z3n105Collectanea
I tried this but not successful. If you log the getChildCount value it always returns 1. If you change the colour you find out that the one child is the selected value and it shows this in the layout inspector as well. Is it the normal NumberPicker that was being used? I also noticed that when the value changed the colour was also lost but returns if you tap on the selected value.Diandiana
check z3n105 answer, this is a better solution as android changes this method and you can not access to this method via reflection nowCamera
@Hartley Thanks for the answer. It changes color of selected field first time number picker is shown. But if I click on number picker or scroll it, colors will return to default color. What is the problem?!Ez
C
40

Not sure why you would need to dive into Java Reflection API for this. Its a simple styling matter. The attribute that you need to override is: textColorPrimary.

<style name="AppTheme" parent="@android:style/Theme.Holo.Light">
    ....
    <item name="android:textColorPrimary">#ff0000</item>
</style>

If you're using the TimePicker inside a Dialog, override android:textColorPrimary in the dialog's theme.

That's about it.

Additional info:

Here's an insightful comment by Yoann Hercouet:

This solution does not change only the color on the NumberPicker, it is a global change that will impact A LOT of components

This is correct, but it overlooks the possibilities I am hinting at. Moreover, global implies app-wide impact. That can be limited to activity-scope by applying this theme only to activities containing the NumberPicker. But, I agree, this may still be too corrosive.

The idea here is to somehow inject textColorPrimary=INTENDED_COLOR into the theme that will be seen by NumberPicker. There are multiple ways to achieve this. Here's one way:

Define a bare-bone style in res/values/styles.xml:

<style name="NumberPickerTextColorStyle">
    <item name="android:textColorPrimary">@color/intended_color</item>
</style>

Now, create a custom NumberPicker:

public class ThemedNumberPicker extends NumberPicker {

    public ThemedNumberPicker(Context context) {
        this(context, null);
    }

    public ThemedNumberPicker(Context context, AttributeSet attrs) {
        // wrap the current context in the style we defined before
        super(new ContextThemeWrapper(context, R.style.NumberPickerTextColorStyle), attrs);
    }
}

Finally, use ThemedNumberPicker in your layout(s):

<package.name.ThemedNumberPicker
    android:id="@+id/numberPicker"
    ....
    ....
    .... />

We have successfully contained the impact that textColorPrimary=INTENDED_COLOR has on our app.

This is of course just one option. For example, if you were inflating a layout containing a NumberPicker, you could use:

// In this case, the layout contains <NumberPicker... />, not <ThemedNumberPicker... />
LayoutInflater.from(new ContextThemeWrapper(context, R.style.NumberPickerTextColorStyle))
    .inflate(R.layout.number_picker_layout, ...);
Chazan answered 28/3, 2015 at 8:4 Comment(7)
A much better approach.Lobation
@Milad If you can give/post some more details about your app setup, I can probably help you out.Chazan
doesn't work on me either. But using this method worked: #13883207Phi
@HenriquedeSousa Like I said to user Milad - if you can post your style setup, I can probably help you out. Moreover, the answer you linked to doesn't make sense (unfortunately). See my comment on that answer.Chazan
It had to do with using the right LayoutInflater. The one from SystemService would not work.Phi
This solution does not change only the color on the NumberPicker, it is a global change that will impact A LOT of components.Coyote
@YoannHercouet Thank you for pointing this out. Made me realise that my answer may not be as clear as I had thought. Please check the edit I've made to it.Chazan
M
8

Here is a Xamarin Snippet from the answer above with TextSize and TextStyle Bold

public static bool SetNumberPickerTextColorAndSize(NumberPicker numberPicker, Color color, ComplexUnitType complexUnitType, float textSize, TypefaceStyle style)
    {
        int count = numberPicker.ChildCount;
        for (int i = 0; i < count; i++)
        {
            View child = numberPicker.GetChildAt(i);
            if (child.GetType() == typeof(EditText))
            {
                try
                {
                    Field selectorWheelPaintField = numberPicker.Class
                                                                .GetDeclaredField("mSelectorWheelPaint");
                    selectorWheelPaintField.Accessible = true;

                    EditText editText = (EditText) child;
                    editText.SetTextSize(complexUnitType, textSize);
                    editText.SetTypeface(editText.Typeface, style);
                    editText.SetTextColor(color);

                    Paint paint = (Paint) selectorWheelPaintField.Get(numberPicker);
                    paint.TextSize =  TypedValue.ApplyDimension(complexUnitType, textSize, numberPicker.Resources.DisplayMetrics);
                    paint.Color = color;
                    paint.SetTypeface(editText.Typeface);

                    numberPicker.Invalidate();
                    return true;
                }
                catch (NoSuchFieldException e)
                {
                    Log.Warn("setNumberPickerTextColor", e);
                }
                catch (IllegalAccessException e)
                {
                    Log.Warn("setNumberPickerTextColor", e);
                }
                catch (IllegalArgumentException e)
                {
                    Log.Warn("setNumberPickerTextColor", e);
                }
            }
        }
        return false;
    }
Melchior answered 30/10, 2014 at 15:32 Comment(4)
ComplexUnitType class not foundPedicab
Where do you call this? From a custom renderer?Decorator
I can't find addView inside the code of NumberPicker.Mowery
Thank you so much! Been looking for this for a while. If anyone is using Xamarin.Android, you put this snippet inside your MainActivity or Fragment. You get your numberpicker with FindViewById, and pass it to the method.Kennethkennett
O
8

For me setting android:textColorPrimary in my theme did nothing, looking at the source code for the NumberPicker it decides the text color from the EditText input thus one need to set the android:editTextColor instead.

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:editTextColor">@color/dark_gray</item>
</style>
Outspan answered 4/7, 2019 at 9:53 Comment(1)
I believe Dinidiniz already pointed that out.Cristen
S
5

Instead of changing every text color to the color you want, better just changing all editText color. NumberPicker actually has a child EditText that display the numbers.

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
        <!-- Change edit color here. -->
        <item name="android:editTextColor">#000000</item>
</style>

This worked for me. And although I have white text in the buttons, they havent changed.

Southwest answered 12/11, 2015 at 14:28 Comment(1)
Hi, I want to just change selected edittext color, does your code do that?Ez
S
4

Based on reflection reject on Android SDK >= 29 better to modify Simon's answer:

public void setNumberPickerTextColor(NumberPicker numberPicker, int color){

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {

        final int count = numberPicker.getChildCount();
        for (int i = 0; i < count; i++) {
            View child = numberPicker.getChildAt(i);
            if (child instanceof EditText) {
                try {
                    ((EditText) child).setTextColor(color);
                    numberPicker.invalidate();

                    Field selectorWheelPaintField = numberPicker.getClass().getDeclaredField("mSelectorWheelPaint");
                    boolean accessible = selectorWheelPaintField.isAccessible();
                    selectorWheelPaintField.setAccessible(true);
                    ((Paint) selectorWheelPaintField.get(numberPicker)).setColor(color);
                    selectorWheelPaintField.setAccessible(accessible);
                    numberPicker.invalidate();

                    Field selectionDividerField = numberPicker.getClass().getDeclaredField("mSelectionDivider");
                    accessible = selectionDividerField.isAccessible();
                    selectionDividerField.setAccessible(true);
                    selectionDividerField.set(numberPicker, null);
                    selectionDividerField.setAccessible(accessible);
                    numberPicker.invalidate();
                } catch (Exception exception) {
                    Logger.exc(exception);
                }
            }
        }
    } else {

        numberPicker.setTextColor(color);
    }
}

In SDK >= 29 NumberPicker have .setTextColor() method.

Steato answered 4/7, 2019 at 8:5 Comment(1)
warning Reflective access to mSelectionDivider, which is not part of the public SDK and therefore likely to change in future Android releasesKnecht
M
2

I took the solution of @Andreas Merz and updated his code. The way things were assigned and the functions signatures/calls he used were not found. I am using min API 19. Here is the code that worked for me.

/**
 * Based on https://mcmap.net/q/301312/-change-the-text-color-of-numberpicker
 * @param picker
 * @param color
 * @param unit
 * @param textSize
 * @param typeface
 * @return
 */
private void formatNumberPickerText(NumberPicker picker, int color,
                                    int unit, float textSize,
                                    Typeface typeface) {
    int count = picker.getChildCount();
    for (int i = 0; i < count; i++) {
        View child = picker.getChildAt(i);
        if (child instanceof EditText) {
            try {
                Class clazz = picker.getClass();
                Field field = clazz.getDeclaredField("mSelectorWheelPaint");
                field.setAccessible(true);

                EditText editText = (EditText) child;
                editText.setTextSize(unit, textSize);
                editText.setTypeface(typeface);
                editText.setTextColor(color);

                Paint paint = (Paint) field.get(picker);
                paint.setTextSize(TypedValue.applyDimension(
                        unit, textSize, getResources().getDisplayMetrics()
                ));
                paint.setColor(color);
                paint.setTypeface(typeface);

                picker.invalidate();
                return;

            } catch (IllegalAccessException | NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
    }
}
Mowery answered 15/8, 2017 at 19:12 Comment(1)
NOTE: Andreas code was for Xamarin Android. This answer is for "normal" Android code (Java), as was the original question. In comparison to the accepted answer, it adds setting of typeface and font size.Cristen
C
1

The accepted answer is overly complicated. A much simpler approach that worked for me was to override the: textColorPrimary attribute of the theme I was using.

<style name="Theme.MyTheme" parent="@android:style/Theme.Holo.NoActionBar.Fullscreen" >
        <item name="android:textColorPrimary">#000000</item>
</style>

It did the job quite well!

Chiclayo answered 24/9, 2015 at 19:57 Comment(0)
F
1

For Kotlin users, use this extension function ( Based on @Tapa Save answer ).

fun NumberPicker.changeTextColor(color: Int) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
        val count: Int = childCount
        for (i in 0 until count) {
            val child: View = getChildAt(i)
            if (child is EditText) {
                try {
                    child.setTextColor(color)
                    invalidate()
                    val selectorWheelPaintField: Field = this.javaClass.getDeclaredField("mSelectorWheelPaint")
                    var accessible: Boolean = selectorWheelPaintField.isAccessible
                    selectorWheelPaintField.isAccessible = true
                    (selectorWheelPaintField.get(this) as Paint).color = color
                    selectorWheelPaintField.isAccessible = accessible
                    invalidate()
                    val selectionDividerField: Field = this.javaClass.getDeclaredField("mSelectionDivider")
                    accessible = selectionDividerField.isAccessible()
                    selectionDividerField.isAccessible = true
                    selectionDividerField.set(this, null)
                    selectionDividerField.isAccessible = accessible
                    invalidate()
                } catch (ignore: Exception) { }
            }
        }
    } else {
        textColor = color
    }
}
Flatware answered 9/12, 2021 at 12:26 Comment(0)
O
-2

It's easy with my NumberPicker library.

<com.github.tomeees.scrollpicker.ScrollPicker
    ...
    app:textColor="..."
    />
Odey answered 22/9, 2018 at 9:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.