Android 更改 NumberPicker 分隔线颜色

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24233556/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:54:42  来源:igfitidea点击:

Changing NumberPicker divider color

androidandroid-stylesnumberpicker

提问by Laurent

On recent android versions, number pickersuse a blue divider when drawn (cf. image below).

在最近的 android 版本中,数字选择器在绘制时使用蓝色分隔线(参见下图)。

enter image description here

在此处输入图片说明

I would like to change this color. Is there a working solution? or perhaps a library that package an updated version of NumberPicker that allows customizing the divider color?

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

I have tried android-numberpickerbut I get an error (see below) at runtime due to some code from the library that tries to access to a resource id that does not exist.

我尝试过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)

采纳答案by Margarita Litkevych

Based on this (https://stackoverflow.com/a/20291416/2915480although it's about DatePicker) there are several ways:

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

  1. Write your own NumberPicker without mSelectionDivider and its affiliates or use backported by Vikram. In last case:

    1. download from lib from github
    2. change drawable in res/drawable-xxx/np_numberpicker_selection_divider.9.png:

      • to transparent (or whatever) .9.png
      • create np_numberpicker_selection_divider.xml shape line resource in res/drawable (with 0dpheight or transparent color).
    3. OR remove if (mSelectionDivider != null)branch from onDraw(Canvas) method in NumberPicker.javalike here

  2. Use reflection to access private final field mSelectionDivider(details: https://github.com/android/platform_frameworks_base/blob/master/core/java/android/widget/NumberPicker.java) - e.g. see modification here. I used reflection but it's not the best solution.

  3. Use theming to override the number picker's divider color in API 21+: ?attr/colorControlNormaldetermines the color of the divider in material number picker, so changing this color in your widget's theme will do the trick, e.g. for DatePicker:

  1. 在没有 mSelectionDivider 及其附属公司的情况下编写您自己的 NumberPicker 或使用Vikram 的反向移植。在最后一种情况下:

    1. github 的lib 下载
    2. 在 res/drawable-xxx/np_numberpicker_selection_divider.9.png 中更改 drawable:

      • 透明(或其他).9.png
      • 在 res/drawable 中创建 np_numberpicker_selection_divider.xml 形状线资源(具有0dp高度或透明颜色)。
    3. 或删除if (mSelectionDivider != null)来自的onDraw(Canvas)的方法分公司NumberPicker.java喜欢这里

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

  3. 在 API 21+ 中使用主题覆盖数字选择器的分隔线颜色:?attr/colorControlNormal确定材料数字选择器中分隔线的颜色,因此在小部件的主题中更改此颜色将起作用,例如对于 DatePicker:

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

and in the widget:

并在小部件中:

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

回答by gabin

If you want simply to change the color (based on stannums answer):

如果您只想更改颜色(基于 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;
        }
    }
}

And after that

在那之后

setDividerColor(mNumberPicker, Color.GREEN);

回答by Rubin Yoo

This worked for me without using the reflection.

这对我有用而不使用反射。

my_layout.xml

my_layout.xml

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

Styles.xml (AppTheme is my app theme in the app)

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

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

回答by stannums

I'm use workaround Java method:

我正在使用解决方法 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;
            }
        }
        //}
     }

or Kotlin method:

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

And apply its

并应用其

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

回答by JDune

I'm fairly new to Android so bear in mind that this solution may not be a good practice, but I found a (hacky) way to get this effect using only XML / WITHOUT reflection.

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

I was able to 'change' the colors of the dividers on my NumberPickers within a LinearLayout by adding 2 thin, horizontal views to the ViewGroup, and giving them negative layout margins and my desired color for their backgrounds:

通过向 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_width="wrap_content"
    android:layout_height="wrap_content"
    >
    <NumberPicker
        android:layout_width="70dip"
        android:layout_height="wrap_content"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:layout_gravity="center"
        android:layout_margin="5dp"
        />

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

    </View>

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

    </View>

</LinearLayout>

Admittedly, I'm not actually changing the color, but adding new lines with my desired color on top of the built-in dividers. Hopefully this helps someone anyway!

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

You may have to play with the margins, but these settings were perfect for my custom dialog.

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

回答by Bojan Kseneman

You can use reflection to do the trick. Here is my solution

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

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

        }
    }
}

回答by SerSánGal

I use the below code to change the divider, not directly the color, but you can do that with a png like this.

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

This solution that I bring you comes from here, but my code is a easy simplification to change the divider and that's it.

我给你带来的这个解决方案来自这里,但我的代码是改变分隔符的简单简化,就是这样。

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

回答by Tamás Sajti

It's easy with my library(I rolled my own NumberPicker too).

我的图书馆很容易(我也推出了自己的 NumberPicker)。

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

回答by 0neel

It's better to store a private field if you are going to change divider color in future. Like this:

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

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

回答by Alireza Taghizadeh

using this code for evry thing u want do with divider

将此代码用于您想用分隔符做的每一件事

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