关于android:更改NumberPicker的文本颜色

Change the text color of NumberPicker

我已经看过大多数关于此的线程,但没有一个提供有效的答案。 设置NumberPicker的样式无效(按照此线程:NumberPicker textColour)

将numberPicker上的style属性设置为具有颜色项的样式也不起作用。 在numberPicker XML上设置textColor属性也不会做任何事情。

我最接近的是使用numberPicker将其getChildAt()转换为EditText,然后对该EditText进行setColor(),但这只会在初始化后更改子项的颜色,然后每次从子项中选择子项的颜色。 在其上 不是我要找的东西。

有什么帮助吗? 谢谢


我尝试为我工作的解决方案是:

在styles.xml中添加:

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

然后在您的布局中像这样使用它:

1
2
3
4
5
6
  <NumberPicker
    android:id="@+id/dialogPicker"
    android:theme="@style/AppTheme.Picker"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="15dp" />


这段代码应该可以解决您的问题。您遇到的问题是因为在构造NumberPicker的过程中,它将捕获EditText textColor并将其分配给绘画,以便它可以使用相同的颜色在编辑文本的上方和下方绘制数字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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();  
}


不知道为什么您需要为此使用Java Reflection API。这是一个简单的样式问题。您需要覆盖的属性是:textColorPrimary

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

如果在Dialog中使用TimePicker,请在对话框主题中覆盖android:textColorPrimary

就是这样

附加信息:

这是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

这是正确的,但它忽略了我所暗示的可能性。此外,global表示对整个应用程序都有影响。通过仅将此主题应用于包含NumberPicker的活动,可以将其限制为活动范围。但是,我同意,这可能仍然具有腐蚀性。

这里的想法是将textColorPrimary=INTENDED_COLOR注入到NumberPicker将看到的主题中。有多种方法可以实现此目的。这是一种方法:

res/values/styles.xml中定义准系统样式:

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

现在,创建一个自定义NumberPicker

1
2
3
4
5
6
7
8
9
10
11
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);
    }
}

最后,在您的布局中使用ThemedNumberPicker

1
2
3
4
5
<package.name.ThemedNumberPicker
    android:id="@+id/numberPicker"
    ....
    ....
    .... />

我们已经成功地包含了textColorPrimary=INTENDED_COLOR对我们的应用程序的影响。

当然,这只是一种选择。例如,如果要夸大包含NumberPicker的布局,则可以使用:

1
2
3
// In this case, the layout contains <NumberPicker... />, not <ThemedNumberPicker... />
LayoutInflater.from(new ContextThemeWrapper(context, R.style.NumberPickerTextColorStyle))
    .inflate(R.layout.number_picker_layout, ...);


这是上面答案中的Xamarin代码片段,具有TextSize和TextStyle Bold

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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;
    }


不必将每种文本颜色更改为所需的颜色,最好只更改所有editText颜色。 NumberPicker实际上有一个显示数字的子EditText。

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

这对我有用。尽管我的按钮中有白色文字,但它们没有改变。


对我而言,在主题中设置android:textColorPrimary并没有执行任何操作,而是查看NumberPicker的源代码,它决定了EditText输入的文本颜色,因此需要设置android:editTextColor

1
2
3
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:editTextColor">@color/dark_gray</item>
</style>


基于Android SDK> = 29上的反射拒绝,最好修改Simon的答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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);
    }
}

在SDK> = 29中,NumberPicker具有.setTextColor()方法。


我采用@Andreas Merz的解决方案并更新了他的代码。事物分配的方式以及他使用的功能签名/调用均未找到。我正在使用min API 19。这是对我有用的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
 * 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();
            }
        }
    }
}


公认的答案过于复杂。对我有用的一种简单得多的方法是覆盖我正在使用的主题的textColorPrimary属性。

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

它做得很好!


使用我的NumberPicker库很容易。

1
2
3
4
<com.github.tomeees.scrollpicker.ScrollPicker
    ...
    app:textColor="..."
    />