更改 NumberPicker 分隔线颜色

Posted

技术标签:

【中文标题】更改 NumberPicker 分隔线颜色【英文标题】:Changing NumberPicker divider color 【发布时间】:2014-08-05 16:19:03 【问题描述】:

在最近的 android 版本中,number pickers 在绘制时使用蓝色分隔线(参见下图)。

我想改变这个颜色。有可行的解决方案吗?或者可能是一个包含允许自定义分隔线颜色的 NumberPicker 更新版本的库?

我已经尝试过android-numberpicker,但由于库中的一些代码尝试访问不存在的资源 ID,因此在运行时出现错误(见下文)。

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)

【问题讨论】:

这能回答你的问题吗?:***.com/questions/18804762/… 不,它不起作用。旨在创建自定义样式的第一个答案不起作用,因为无法解析符号“@style/Holo.NumberPicker”。对于第二个答案,结果是一样的:在反射检索到的字段 mSelectionDivider 上调用 set(numberPicker, color) 没有效果。 【参考方案1】:

科特林

您可以通过这种方式更改分隔符编号,而无需版本控制。本例设置透明颜色:

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()
    

【讨论】:

【参考方案2】:

其实你可以写一个自定义主题来改变分隔线的颜色。

作为示例将其添加到您的主题.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>

并将这个主题添加到您的 Numberpicker

<NumberPicker
        android:id="@+id/index_picker1"
        android:layout_
        android:layout_
        android:theme="@style/NumberPickerTheme"
         />

如果你想摆脱分隔线,只需使用

<item name="colorControlNormal">@android:color/transparent</item>

【讨论】:

【参考方案3】:

基于此(https://***.com/a/20291416/2915480 虽然是关于 DatePicker)有几种方法:

    在没有 mSelectionDivider 及其附属机构的情况下编写您自己的 NumberPicker,或使用 Vikram 的反向移植。最后一种情况: 从github的lib下载 更改 res/drawable-xxx/np_numberpicker_selection_divider.9.png 中的可绘制对象:
透明(或其他).9.png * 在 res/drawable 中创建 np_numberpicker_selection_divider.xml 形状线资源(带有0dp 高度或透明颜色)。

    或从NumberPicker.java 中的onDraw(Canvas) 方法中删除if (mSelectionDivider != null) 分支,例如here

    使用反射访问private final field mSelectionDivider(详细信息:https://github.com/android/platform_frameworks_base/blob/master/core/java/android/widget/NumberPicker.java) - 例如见修改here。 我使用了反射,但这不是最好的解决方案。

    在 API 21+ 中使用主题来覆盖数字选择器的分隔线颜色:?attr/colorControlNormal 确定材料编号选择器中分隔线的颜色,因此在小部件的主题中更改此颜色即可,例如对于日期选择器:

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

在小部件中:

 <DatePicker
        android:id="@+id/question_date"
        android:layout_
        android:layout_ 
        android:calendarViewShown="false"
        android:datePickerMode="spinner"
        android:gravity="center"
        android:theme="@style/MyAppTheme.NumberPicker" />

【讨论】:

感谢您的帮助。解决方案 2 完美运行,但我未能使解决方案 1 工作。最后,与 NumberPicker.java 中的变量 DEFAULT_LAYOUT_RESOURCE_ID 关联的资源 ID 似乎不再有效。最后但同样重要的是,我的目标是将颜色更改为自定义颜色,而不是隐藏分隔线。为了实现这个目标,我没有将mSelectionDivider 设置为null,但等于一个drawable,它是一个简单的九个补丁PNG,加载了getResources().getDrawable(R.drawable.np_numberpicker_selection_divider)【参考方案4】:

我正在使用解决方法 Java 方法:

  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;
            
        
        //
     

或 Kotlin 方法:

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()
    

并应用其

  setDividerColor(yourNumberPicker); // for java method
  yourNumberPicker.setDividerColor(Color.RED) // for kotlin method

【讨论】:

【参考方案5】:

使用我的library 很容易(我也推出了自己的 NumberPicker)。

<com.github.tomeees.scrollpicker.ScrollPicker
    ...
    app:selectorColor="..."
    />

【讨论】:

com.github.tomeees.scrollpicker.ScrollPicker 及其 app:selectorColor 运行良好,感谢您制作 Tamás Sajti【参考方案6】:

如果您将来要更改分隔线颜色,最好存储一个私有字段。像这样:

@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) 

【讨论】:

【参考方案7】:

这在不使用反射的情况下对我有用。

my_layout.xml

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

Styles.xml(AppTheme是我在应用中的应用主题)

<style name="DefaultNumberPickerTheme" parent="AppTheme">
        <item name="colorControlNormal">@color/dividerColor</item>
</style>

【讨论】:

只是一个友好的提醒。 'colorControlNormal',仅适用于 API 21 及更高版本。 如果存在“colorControlNormal”,请提出替代方案 只是想指出使用colorControlNormal 对我不起作用,我必须明确添加android: 前缀,就像&lt;item name="android:colorControlNormal"&gt;#ffffff&lt;/item&gt;【参考方案8】:

我对 Android 还很陌生,所以请记住,这种解决方案可能不是一个好的做法,但我找到了一种(hacky)方法来获得这种效果,只使用 XML/不使用反射。

通过向 ViewGroup 添加 2 个薄的水平视图,并为它们提供负布局边距和我想要的背景颜色,我能够“更改”LinearLayout 内 NumberPickers 上分隔线的颜色:

<?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_
    android:layout_
    >
    <NumberPicker
        android:layout_
        android:layout_
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:layout_gravity="center"
        android:layout_margin="5dp"
        />

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

    </View>

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

    </View>

</LinearLayout>

诚然,我实际上并没有改变颜色,而是在内置分隔线的顶部添加了我想要的颜色的新线条。希望这对某人有所帮助!

您可能不得不使用边距,但这些设置非常适合我的自定义对话框。

【讨论】:

【参考方案9】:

最简单的方法是在 xml 中的 NumberPicker 选择器中添加此属性

android:selectionDivider="@colors/your_color"

【讨论】:

【参考方案10】:

您可以使用反射来解决问题。这是我的解决方案

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) 

        
    

【讨论】:

我认为这是最好的答案。另外,我认为这对于仅自定义一条线来说太过分了……但那是系统故障。你帮了我很多。谢谢【参考方案11】:

将此代码用于您想用分隔符做的所有事情

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;
                
            

【讨论】:

【参考方案12】:

如果您只想更改颜色(基于 stannums 答案):

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;
        
    

然后

setDividerColor(mNumberPicker, Color.GREEN);

【讨论】:

不错的变化。我注意到的一件事是确保使用 'newColorDrawable(ctx.getResources().getColor(R.color.whatevercolor))' 而不是 'new ColorDrawable(R.color.whatevercolor)' 我真的认为,它应该标记为尝试答案!它真的很简单而且很有效! 可能会更好:ColorDrawable colorDrawable = new ColorDrawable(ContextCompat.getColor(getContext(), R.color.primaryColor)); 谢谢伙计!我把它翻译成一个 Kotlin 扩展,它工作得很好。【参考方案13】:

我使用下面的代码来改变分隔线,而不是直接改变颜色,但你可以用 png like this 来做到这一点。

我给你带来的这个解决方案来自here,但是我的代码是一个简单的简化来改变分隔符,仅此而已。

    // 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;
        
    

【讨论】:

以上是关于更改 NumberPicker 分隔线颜色的主要内容,如果未能解决你的问题,请参考以下文章

更改 android numberpicker 分隔线颜色

更改 NumberPicker 的文本颜色

Android numberpicker里的线可以改颜色吗

Android的NumberPicker那两天蓝色的线如何更换颜色

AsymmetricGridView 更改垂直分隔线颜色

如何更改 Android ListView 分隔线的颜色?