安卓:如何改变枣子分隔器的颜色?

我的Android应用程序中有一个日期选择器,但现在我想将蓝色分隔线的颜色更改为绿色(请参阅此文本下方的图像)。关于Stackoverflow还有其他一些讨论,但都没有给出导致解决方案的答案。

所以我去寻找自己,发现实际上有一个android:datePickerStyle,还有一个android:divider。但是,我不知道分隔符是否真的是指日期选择器中的分隔符。我尝试了两者的多种组合,但我似乎无法使其正常工作。所以我的第一个问题是:android:divider是指日期选择器中的分隔器吗,我怎么能用它来改变颜色?

因此,另一种选择应该是创建一个全新的自定义日期拾取器。如果这让我能够改变分隔线的颜色,我就为此感到失望。因此,我看了一些关于 创建自定义日期拾取器的教程,但似乎没有一个定义分隔符的颜色。分隔符根本不列在 xml 文件或 java 文件中。

如果有某种样板代码来重新创建当前显示的日期拾取器,包括设置分隔符颜色的代码,那就太好了。希望这能让我复制它,并简单地改变某个地方分隔符的颜色设置。所以我的第二个问题:有人会知道任何样板代码,它只是像现在这样实现datepicker(包括分隔符的定义)吗?

enter image description here


答案 1

不幸的是,这不是一项微不足道的任务。

DatePickers使用小部件和内部。例如,您发布的图像使用 3 。你说的分隔线来自NumberPicker的属性:。问题在于此属性不是公共的,也不是 ,通过它设置此属性。NumberPickerCalendarViewNumberPickersselectionDividernumberPickerStyle

我最近将CalendularView和NumberPicker移植到API 8,主要是为了好玩。由于代码是现成的(在Android的源代码中查找和其他代码),因此所有这些任务只需要时间,并且需要一些挖掘Android的源代码。例子:android.widget.NumberPicker

  1. 简单 ==> 您必须将私有变量从 View 类更改为其访问器方法

    mLeft(View 类中的受保护变量)==> getLeft() (公共访问器方法)

  2. 最耗时的任务是还原辅助功能方法。

无论如何,如果您决定编写DatePicker的自定义实现,则必须为NumberPicker和CalendarView(可选)编写它们。

更简单的方法:

Backported DatePicker可作为库在这里找到:Android-DatePicker。如上所述,您将与此 DatePicker 结合使用向后移植的 CalendarView 和 NumberPicker。

您需要更改的内容:

用作模板,并将“蓝色”颜色更改为绿色(我使用pixlr)。如果要完全使用蓝色分隔符,则可以使用相同的名称保存它,也可以使用其他名称并在 中进行更改。{library-numberpicker} / res / drawable-xxxx / np_numberpicker_selection_divider.9.png{library-numberpicker} / res / values / themes.xml

如果选择其他名称,则需要进行的更改:themes.xml

<style name="NPWidget.Holo.NumberPicker" parent="NPWidget.NumberPicker">
    ....
    <item name="selectionDivider">@drawable/new_nine_path_drawable_name</item>
    ....
</style>

就是这样。

使用库输出:

enter image description here

编辑:

是否是指枣子中的分隔线,我如何使用它来改变颜色?android:divider

该属性实际上来自 。 将此属性继承为 。但这有不同的目的。传递给此属性的可绘制对象放置在 的子视图之间。dividerLinearLayoutNumberPickerNumberPicker extends LinearLayoutdividerLinearLayout

该属性用于更改此分隔符的位置,可能的值为:android:showDividers

  • 无:未显示分频器
  • 开始:分隔线显示在第一个子视图之前
  • 中间:分隔线显示在每个子视图之后,而不是在最后一个子视图之后
  • 结束:分隔线显示在最后一个子视图之后

该属性是不言自明的。android:dividerPadding

即使 NumberPicker 继承此属性,它也不会使用它。从你自己的研究和试验中可以明显看出这一点:I tried a multitude of combinations of the two, but I don't seem to get it to work.

要查看实际操作中的分隔符属性,请执行以下操作:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:divider="@android:drawable/ic_media_play"
    android:showDividers="middle" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="World," />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Again" />

</LinearLayout>

使用java反射的黑客式解决方法:

这个答案给了我这个想法。我讨厌使用refection,主要是因为这个答案中列出的原因:链接。虽然我在这里列出它是为了完整性,但我建议你不要使用它。

public class CDP extends android.widget.DatePicker {

    public CDP(Context context, AttributeSet attrs) {
        super(context, attrs);

        Class<?> internalRID = null;
        try {
            internalRID = Class.forName("com.android.internal.R$id");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Field month = null;
        try {
            month = internalRID.getField("month");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        NumberPicker npMonth = null;
        try {
            npMonth = (NumberPicker) findViewById(month.getInt(null));
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        Field day = null;
        try {
            day = internalRID.getField("day");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        NumberPicker npDay = null;
        try {
            npDay = (NumberPicker) findViewById(day.getInt(null));
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        Field year = null;
        try {
            year = internalRID.getField("year");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        NumberPicker npYear = null;
        try {
            npYear = (NumberPicker) findViewById(year.getInt(null));
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        Class<?> numberPickerClass = null;
        try {
            numberPickerClass = Class.forName("android.widget.NumberPicker");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Field selectionDivider = null;
        try {
            selectionDivider = numberPickerClass.getDeclaredField("mSelectionDivider");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        try {
            selectionDivider.setAccessible(true);
            selectionDivider.set(npMonth, getResources().getDrawable(
                       R.drawable.np_numberpicker_selection_divider_green));
            selectionDivider.set(npDay, getResources().getDrawable(
                       R.drawable.np_numberpicker_selection_divider_green));
            selectionDivider.set(npYear, getResources().getDrawable(
                       R.drawable.np_numberpicker_selection_divider_green));
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (NotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

我们在这里做什么:

  • 延长日期拾取器
  • 如果在 中打开,您将看到三个 NumberPickers 具有 id 、 、 。我们访问以获取这些 NumberPickers 的资源 ID。date_picker.xmlsdk/platforms/android-xx/res/layoutmonthdayyearandroid.internal.R.id
  • 我们使用这些带有方法的 id 创建三个 NumberPicker 对象。findViewById(int)
  • 然后,使用 relection 访问和检索字段。mSelectionDivider
  • 将字段设置为可访问(作为其声明的最终字段),使用方法设置其值。第一个参数是我们对其执行此操作的对象。第二个参数是我们要设置的对象。Field#set(Object, Object)

我使用的可绘制文件可以从以下位置下载:这里


答案 2

我认为最简单的解决方案可能是使用样式。

只需将其放入您的样式中.xml文档

    <!-- changes the default colours for EditTexts, including non-text elements (also works with the DatePicker -->

<style name="appCompatStyle" parent="Theme.AppCompat.Light">
    <item name="colorControlNormal">@color/lightPrimaryText</item>
    <item name="colorControlActivated">@color/colorAccent</item>
    <item name="android:editTextStyle">@style/editTextStyle</item>
</style>


<!-- changes the default text colour for the EditTexts -->
<style name="editTextStyle" parent="android:style/Widget.EditText">
    <item name="android:textColor">@color/lightPrimaryText</item>
</style>

并将这些属性放在布局 XML 中

android:theme="@style/appCompatStyle"

并按照您喜欢的方式进行自定义。


推荐