Change the text color of NumberPicker
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
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" />
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();
}
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, ...);
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;
}
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>