Android:如何更改日期选择器分隔线的颜色?

39
我在我的Android应用中有一个日期选择器,但现在我想将蓝色分隔线的颜色更改为绿色(请参见下面这段文字下面的图像)。在Stackoverflow上有some other discussions谈论相同的问题,但它们都没有给出解决方案的答案。
所以我开始自己寻找,发现实际上有一个android:datePickerStyle和一个android:divider。然而,我不知道divider是否真的与datepicker中的divider有关。我尝试了许多组合,但似乎无法使其正常工作。因此,我的第一个问题是:android:divider是否指的是datepicker中的divider,并且我该如何使用它来更改颜色? 所以另一个选项是创建全新的自定义日期选择器。如果这使我只需更改分隔线颜色,我就可以接受。因此,我查看了一些有关创建自定义日期选择器的教程some of the tutorials,但是它们似乎都没有定义分隔线的颜色。在xml文件或java文件中,分隔线根本没有列出。
希望能有一些样板代码来重新创建日期选择器,包括设置分隔线颜色的代码。希望这能让我复制它并在某处简单地更改分隔线的颜色设置。所以我的第二个问题是:是否有人知道任何样板代码,可以将日期选择器简单实现为现在的样子(包括定义分隔线)?

enter image description here


这个链接可能对你有帮助,请查看一下:https://dev59.com/9mcs5IYBdhLWcg3wmlOk - Nagaraja
8个回答

101

很遗憾,这不是一项微不足道的任务。

DatePickers在内部使用小部件NumberPickerCalendarView。例如,您发布的图像正在使用3个NumberPickers。而您所说的分隔符来自于NumberPicker属性:selectionDivider。问题在于,此属性不是公共属性,numberPickerStyle也不是,通过它设置该属性。

我最近将CalendarViewNumberPicker向后移植到API 8中,主要是为了好玩。由于代码readily可用(查找android源代码中的android.widget.NumberPicker等),所有这个任务只需要时间和一些挖掘android源代码即可。例如:

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

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

  2. 最耗时的任务是恢复Accessibility方法。

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

更容易的方法:

向后移植的DatePicker可在此处作为库使用:Android-DatePicker。如上所述,您将与此DatePicker一起使用后向移植的CalendarViewNumberPicker

您需要更改的内容:

使用{library-numberpicker} / res / drawable-xxxx / np_numberpicker_selection_divider.9.png作为模板,将“蓝色”颜色更改为绿色(我使用了pixlr)。如果您想彻底摆脱蓝色分隔符,可以直接保存相同名称的文件,或者使用不同的名称并在{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>

就是这样了。

使用库输出:

输入图像描述

编辑:

android:divider 是指 datepicker 中的分隔符吗?我如何使用它来更改颜色?

divider 属性实际上来自于 LinearLayoutNumberPicker 继承了此属性,因为 NumberPicker 扩展了 LinearLayout。但是,此 divider 具有不同的用途。传递给此属性的 drawable 位于 LinearLayout 的子视图之间。

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

  • none: 不显示分隔符
  • beginning: 在第一个子视图之前显示分隔符
  • middle: 在每个子视图之后显示分隔符,但不在最后一个子视图之后显示
  • end: 在最后一个子视图之后显示分隔符

android:dividerPadding 属性很容易理解。

虽然 NumberPicker 继承了此属性,但它不使用它。这可以从您自己的研究和试验中看出: 我尝试了各种组合,但似乎无法使其工作。

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

<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反射的hack-ish解决方法:

这个回答在这里给了我灵感。总的来说,我讨厌使用反射,主要是因为这个答案中列出的原因。虽然我在此处列出它以保证完整性,但我建议您不要使用它。

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

我们在这里做的事情:

  • 扩展DatePicker
  • 如果您在sdk/platforms/android-xx/res/layout中打开date_picker.xml,则会看到三个NumberPicker具有id monthdayyear。我们访问android.internal.R.id以获取这些NumberPickers的资源id。
  • 我们使用这些id使用findViewById(int)方法创建三个NumberPicker对象。
  • 然后,使用反射访问和检索字段mSelectionDivider
  • 将该字段设置为可访问的(因为它被声明为final),并使用Field#set(Object, Object)方法设置其值。第一个参数是我们执行此操作的对象。第二个参数是我们要设置的对象。

我使用的可绘制资源可以从此处下载:here


可能的简化:npMonth = (NumberPicker) findViewById(Resources.getSystem().getIdentifier("month", "id", "android")); - Justin Muller
@Vikram,你是怎么把时间选择器(TimePicker)的上下日期文本变成灰色的呢?对我来说,所有文本颜色都是黑色。 - flexdroid
@flexdroid 我不需要将文本颜色变成灰色。从源代码中可以看出,NumberPicker使用以下参数:TOP_AND_BOTTOM_FADING_EDGE_STRENGTH = 0.9f。由于缺乏更好的词语,这个值是应用于特定部分的 Viewalpha,使用重写方法 getTopFadingEdgeStrength()getBottomFadingEdgeStrength()。而获得此 alpha 应用的具体部分是在 NumberPicker#initializeFadingEdges() 中确定的。 - Vikram
@flexdroid,由于您没有看到这种效果,请检查net.simonvt.numberpicker.NumberPicker.java并确认TOP_AND_BOTTOM_FADING_EDGE_STRENGTH确实设置为0.9f。您还可以尝试将此值更改为像0.1f这样的戏剧性数字。在这种情况下,顶部和底部的文本视图应该几乎不可见。 - Vikram
@Vikram 即使我改变了 TOP_AND_BOTTOM_FADING_EDGE_STRENGTH 的值为 0.9f,但我仍然无法看到效果。 - flexdroid
显示剩余4条评论

26

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

只需将此放入您的styles.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"

并且你可以根据自己的喜好进行自定义。


3
在Android 4.3和4.4上不起作用,在Android 5及以上版本中 - 运行良好。 - streamride
2
这不会改变API 21的分隔线颜色。 - mitsest

11

对于我来说,将DatePicker布局设置为一个主题并将其添加到colorControlNormal中是有效的。

在您的布局的XML中添加一个DatePicker,并应用如下所示的主题 -

<DatePicker xmlns:android="http://schemas.android.com/apk/res/android"
            android:theme="@style/NumberPickerStyle"
            android:datePickerMode="spinner"
            android:calendarViewShown="false"
            android:layout_gravity="center_horizontal"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"/>

然后在 styles.xml 中定义 NumberPickerStyle,并指定像这样的 colorControlNormal -

<style name="NumberPickerStyle">
        <item name="colorControlNormal">@color/colorAccent</item>
</style>

我有完全相同的代码,但它不起作用。它仍然是黑色的。但是我没有在对话框中使用DatePicker。它只是我在对话框中显示的一个视图,我不知道这是否会改变任何东西。 - Jack'

8

修改使用 android:datePickerMode="spinner"DatePickerDialog 中的颜色分隔线 => 为 DatePicker 设置 android:theme

DatePicker Xml:

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

MyAppTheme Xml:

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

screenshot


3

他们有一个可以自定义时间和日期选择器的。在其中,您可以按以下方式更改分隔符的颜色。

    timePicker.setSelectionDivider(new ColorDrawable(0xffff0000));
    timePicker.setSelectionDividerHeight(2);

编辑 我曾经使用过另一个,也是一个很好的库,因为你可以在themes.xml中使用以下方式进行自定义。

<style name="NPWidget.Holo.NumberPicker" parent="NPWidget.NumberPicker">
        <item name="solidColor">@android:color/transparent</item>
        <item name="selectionDivider">@color/div_color</item>
        <item name="selectionDividerHeight">0.3dip</item>
        <item name="internalLayout">@layout/number_picker_with_selector_wheel</item>
        <item name="internalMinWidth">64dip</item>
        <item name="internalMaxHeight">140dip</item>
        <item name="virtualButtonPressedDrawable">@drawable/item_background_holo_dark</item>
    </style>

该库崩溃并抛出奇怪的异常。 - Adel Nizamuddin
CustomTimePicker是一款可以完全按照您自己的方式进行定制的选择时间控件。我使用它,效果非常好。 - Rajesh N

0

如果只想更改DatePickerDialog中分隔符的颜色,只需在您的主题中更改android:datePickerDialogTheme样式即可:

主题样式:

 <style name="BaseTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:datePickerDialogTheme">@style/style_date_picker_dialog</item>
</style>

对话框样式:

<style name="style_date_picker_dialog" parent="AppCompatAlertDialogStyle">
<item name="colorControlNormal">@color/colorAccent</item>
</style>

android:datePickerDialogTheme 适用于 API >=21。 - Francisco Romero

0
首先,Vikram,你做得很好,感谢你的努力!我在net.simonvt.datepicker.DatePickerDialog中缺少的一件事是设置titleDivider颜色的选项,我想要与numberPickerDividerColor匹配。因此,我在Vikram的实现中添加了这个选项,并在这里发布。这是一个常见的解决方案,涉及更改AlertDialog.titleDividerColor。也许它会帮助到某些人。
class net.simonvt.datepicker.DatePickerDialog
private int titleDividerColor;

在显示对话框时设置颜色非常重要,因此我会在onAttachedToWindow方法中进行此操作。

@Override
public void onAttachedToWindow() {
    super.onAttachedToWindow();

    if (titleDividerColor <= 0) { return; }

    try {
        int dividerId = getContext().getResources().getIdentifier("android:id/titleDivider", null, null);
        View divider = findViewById(dividerId);
        if (divider != null) {
            divider.setBackgroundColor(getContext().getResources().getColor(titleDividerColor));
        }
    } catch (Exception e) {}
}

public void setTitleDividerColor(int titleDividerColor) {
    this.titleDividerColor = titleDividerColor;
}

public int getTitleDividerColor() {
    return titleDividerColor;
}

编辑

我在这里发布了另一个解决方案 https://dev59.com/B2Yq5IYBdhLWcg3wfgvd#33800696


-5

来自wreckerAndroid分隔线颜色DatePicker对话框

You can use these attributes for instance:

<NumberPicker
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            selectionDivider="@color/black" //The divider for making the selection area
            selectionDividerHeight="1px"//The height of the selection divider
            selectionDividersDistance="3dp"//The distance between the two selection dividers
            internalLayout="@layout/something"//The layout of the number picker.
            internalMaxHeight="5dp"//The max height of the NumberPicker (also check other variations)
            internalMinWidth="5dp" // The max width of the NumberPicker (also check other variations)
            virtualButtonPressedDrawable="@drawable/something"//The drawable for pressed virtual (increment/decrement) buttons.
            />

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接