Reputation: 1858
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
Upvotes: 63
Views: 64130
Reputation: 871
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
}
}
Upvotes: 1
Reputation: 4857
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.
Upvotes: 4
Reputation: 39081
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>
Upvotes: 8
Reputation: 11190
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();
}
Upvotes: 74
Reputation: 80
It's easy with my NumberPicker library.
<com.github.tomeees.scrollpicker.ScrollPicker
...
app:textColor="..."
/>
Upvotes: -2
Reputation: 1971
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://stackoverflow.com/a/26657169/2313889
* @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();
}
}
}
}
Upvotes: 2
Reputation: 1995
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" />
Upvotes: 108
Reputation: 51571
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, ...);
Upvotes: 40
Reputation: 811
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.
Upvotes: 5
Reputation: 1288
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!
Upvotes: 1
Reputation: 89
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;
}
Upvotes: 8