【问题标题】:Android divider color DatePicker dialogAndroid 分隔线颜色 DatePicker 对话框
【发布时间】:2013-09-13 21:27:44
【问题描述】:

我正在尝试更改对话框中 DatePicker 的蓝色分隔线的颜色。这只是一个带有 DatePicker 和 ButtonBar 的普通 DialogFragment。

有谁知道要更改这些分隔线,或者是否可以不用自定义的替换整个 DatePicker?

迷你咆哮

现在我看到太多建议使用以下代码的答案:

<style name="datePickerTheme" parent="@android:style/Widget.DeviceDefault.DatePicker">
    <item name="android:divider">**your @drawable/ or @color/ here**</item>
</style>

这根本行不通。你们在建议这个代码之前有没有试过这个?它应该完美运行,但它似乎不适用于 DatePicker。

【问题讨论】:

    标签: android android-layout colors datepicker divider


    【解决方案1】:

    以下方法对我有用。这会为所有字段设置分隔线颜色(也适用于上午/下午)

     private void applyStyLing(TimePickerDialog timePickerDialog){
        Resources system = Resources.getSystem();
        int hourNumberPickerId = system.getIdentifier("hour", "id", "android");
        int minuteNumberPickerId = system.getIdentifier("minute", "id", "android");
        int ampmNumberPickerId = system.getIdentifier("amPm", "id", "android");
    
        NumberPicker hourNumberPicker = (NumberPicker) timePickerDialog.findViewById(hourNumberPickerId);
        NumberPicker minuteNumberPicker = (NumberPicker) timePickerDialog.findViewById(minuteNumberPickerId);
        NumberPicker ampmNumberPicker = (NumberPicker) timePickerDialog.findViewById(ampmNumberPickerId);
    
       setNumberPickerDividerColour(hourNumberPicker);
       setNumberPickerDividerColour(minuteNumberPicker);
       setNumberPickerDividerColour(ampmNumberPicker);
    }
    
    private void setNumberPickerDividerColour(NumberPicker number_picker){
        final int count = number_picker.getChildCount();
    
        for(int i = 0; i < count; i++){
    
            try{
                Field dividerField = number_picker.getClass().getDeclaredField("mSelectionDivider");
                dividerField.setAccessible(true);
                    ColorDrawable colorDrawable = new ColorDrawable(mContext.getResources().getColor(R.color
                            .interactive_color));
                dividerField.set(number_picker,colorDrawable);
    
                number_picker.invalidate();
            }
            catch(NoSuchFieldException e){
                Log.w("setNumberPickerTxtClr", e);
            }
            catch(IllegalAccessException e){
                Log.w("setNumberPickerTxtClr", e);
            }
            catch(IllegalArgumentException e){
                Log.w("setNumberPickerTxtClr", e);
            }
        }
    }
    

    【讨论】:

    • 即使您将 TimePicker 对象传递给 applyStyLing(),此解决方案也有效,它也会找到子视图。解决方案现在有点长而且很好,至少正在工作,需要更多的支持 +1 :)
    • 虽然不是最好的解决方案,但是它就像魔法一样工作。值得+1。谢谢@Ajit ....是的,棒棒糖前和棒棒糖设备的android样式被破坏了
    • 此解决方案适用于多种设备(4-5 种不同的操作系统和品牌),但 Nexus 5x (7.0) 除外。 timePickerDialog.findViewById(hourNumberPickerId) 返回 null。其他人遇到过这个吗?
    【解决方案2】:

    我通过这样做解决了这个问题:

    我通过找到“mSelectionDivider”将DatePicker 分隔符更改为reflection。然后我遇到了标题分隔符看起来很愚蠢的问题,所以我在LinearLayout 上方添加了一个textview,其中包含3 datepickers 并使用了newFragment.setTitle(""); 删除原来的。

    divider drawable 的示例:感谢制作这个的人! :) http://ge.tt/8wK7TZ71/v/0?c

    Result picture

    例子:

        public DatePickerDialog makeDatePicker(OnDateSetListener listener, Calendar cal) {
        Calendar c;
        if (cal == null) {
            c = Calendar.getInstance();
        } else {
            c = cal;
        }
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH);
        int day = c.get(Calendar.DAY_OF_MONTH);
        DatePickerDialog newFragment = new DatePickerDialog(this, listener, year, month, day);
    
        // removes the original topbar:
        newFragment.setTitle(""); 
    
        // Divider changing:
        DatePicker dpView = newFragment.getDatePicker(); 
        LinearLayout llFirst = (LinearLayout) dpView.getChildAt(0);
        LinearLayout llSecond = (LinearLayout) llFirst.getChildAt(0);
        for (int i = 0; i < llSecond.getChildCount(); i++) {
            NumberPicker picker = (NumberPicker) llSecond.getChildAt(i); // Numberpickers in llSecond
            // reflection - picker.setDividerDrawable(divider); << didn't seem to work.
            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.np_numberpicker_selection_divider_orange));
                    } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                    } catch (NotFoundException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    break;
                }
            }
        }
        // New top:
        int titleHeight = 90;
        // Container:
        LinearLayout llTitleBar = new LinearLayout(this);
        llTitleBar.setOrientation(LinearLayout.VERTICAL);
        llTitleBar.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, titleHeight));
    
        // TextView Title:
        TextView tvTitle = new TextView(this);
        tvTitle.setText("Select a date");
        tvTitle.setGravity(Gravity.CENTER);
        tvTitle.setPadding(10, 10, 10, 10);
        tvTitle.setTextSize(24);
        tvTitle.setTextColor(Color.BLACK);
        tvTitle.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, titleHeight-2));
        llTitleBar.addView(tvTitle);
    
        // View line:
        View vTitleDivider = new View(this);
        vTitleDivider.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 2));
        vTitleDivider.setBackgroundColor(getResources().getColor(R.color.crumblrOrange));
        llTitleBar.addView(vTitleDivider);
    
        dpView.addView(llTitleBar);
        FrameLayout.LayoutParams lp = (android.widget.FrameLayout.LayoutParams) llFirst.getLayoutParams();
        lp.setMargins(0, titleHeight, 0, 0);
        return newFragment;
    }
    

    【讨论】:

    • 不适用于 28+ API。 developer.android.com/about/versions/10/non-sdk-q?authuser=1
    【解决方案3】:

    我将此代码基于Ajit's answer,但我将其调整为DatePicker 而不是TimePicker。此外,为了安全起见,我添加了null 支票:

    public static void colorizeDatePicker(DatePicker datePicker) {
        Resources system = Resources.getSystem();
        int dayId = system.getIdentifier("day", "id", "android");
        int monthId = system.getIdentifier("month", "id", "android");
        int yearId = system.getIdentifier("year", "id", "android");
    
        NumberPicker dayPicker = (NumberPicker) datePicker.findViewById(dayId);
        NumberPicker monthPicker = (NumberPicker) datePicker.findViewById(monthId);
        NumberPicker yearPicker = (NumberPicker) datePicker.findViewById(yearId);
    
        setDividerColor(dayPicker);
        setDividerColor(monthPicker);
        setDividerColor(yearPicker);
    }
    
    private static void setDividerColor(NumberPicker picker) {
        if (picker == null)
            return;
    
        final int count = picker.getChildCount();
        for (int i = 0; i < count; i++) {
            try {
                Field dividerField = picker.getClass().getDeclaredField("mSelectionDivider");
                dividerField.setAccessible(true);
                ColorDrawable colorDrawable = new ColorDrawable(picker.getResources().getColor(R.color.colorAccent));
                dividerField.set(picker, colorDrawable);
                picker.invalidate();
            } catch (Exception e) {
                Log.w("setDividerColor", e);
            }
        }
    }
    

    输出

    【讨论】:

    【解决方案4】:

    这解决了我在应用主题样式中添加以下代码行的问题。

    <item name="colorControlNormal">@color/colorAccent</item>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
      <item name="colorControlNormal">@color/blue</item> 
    </style>
    

    【讨论】:

    • 漂亮干净。谢谢
    • 为我工作!!谢谢!!
    • 该方法不适用于 API Level 21 模拟器。但在 API 级别 23 模拟器和 API 级别 29 设备(基本电话)上工作正常!!在布局xml中:&lt;NumberPicker app:theme="@style/AppTheme.NumberPicker" /&gt;在styles.xml中:&lt;style name="AppTheme.NumberPicker"&gt;&lt;item name="colorControlNormal"&gt;@color/themeColor&lt;/item&gt;&lt;/style&gt;
    【解决方案5】:

    考虑:

    你不需要新的 R.drawable.divider

    你可以写:

     pf.set(number_picker, new ColorDrawable(getResources().getColor(R.color.red)));
    

    【讨论】:

    • 不适用于 28+ API。 developer.android.com/about/versions/10/non-sdk-q?authuser=1
    【解决方案6】:

    此版本已针对 DatePicker 的特定用途进行了调整。虽然 Andrea Lazzarotto 的 版本运行良好,但它使用了一个不必要的循环,导致颜色变化的多次应用。除了小的代码改进外,我的版本使用应用程序主题的原色来匹配分隔线颜色(请参阅How can I get the primary color from my app theme?)。使用 Android 6.0 和 8.0 测试:

    private void colorizeDatePicker(final DatePicker datePicker) {
        final Resources system = Resources.getSystem();
        final String defType = "id";
        final String defPackage = "android";
    
        final int dayId = system.getIdentifier("day", defType, defPackage);
        final int monthId = system.getIdentifier("month", defType, defPackage);
        final int yearId = system.getIdentifier("year", defType, defPackage);
    
        final NumberPicker dayPicker = (NumberPicker) datePicker.findViewById(dayId);
        final NumberPicker monthPicker = (NumberPicker) datePicker.findViewById(monthId);
        final NumberPicker yearPicker = (NumberPicker) datePicker.findViewById(yearId);
    
        setDividerColor(dayPicker);
        setDividerColor(monthPicker);
        setDividerColor(yearPicker);
    }
    
    private void setDividerColor(final NumberPicker picker) {
        if (picker == null) {
            return;
        }
    
        try {
            final Field dividerField = picker.getClass().getDeclaredField("mSelectionDivider");
            dividerField.setAccessible(true);
    
            final TypedValue outValue = new TypedValue();
            getContext().getTheme().resolveAttribute(R.attr.colorPrimary, outValue, true);
            final int dividerColor = outValue.data;
    
            dividerField.set(picker, new ColorDrawable(dividerColor));
            picker.invalidate();
        } catch (Exception e) {
        }
    }
    

    【讨论】:

    • 这应该是公认的答案。谢谢@Michael Troger
    • 不适用于 28+ API。 developer.android.com/about/versions/10/non-sdk-q?authuser=1
    【解决方案7】:

    是的,当然可以。例如,您可以使用这些属性:

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

    更新:

    您可以使用此custom datepicker。它具有高度可定制性和向后竞争性。它基本上使用数字选择器,您可以使用上面的属性设置分隔符。

    【讨论】:

    • 这是 NumberPicker 的代码,DatePicker 似乎没有 selectionDivider 属性?编辑:...这也会给 NumberPicker 带来错误?
    • android:selectionDivider 似乎是 Number- 和 DatePicker 的私有属性,我无法更改它。
    • 我已经更新了我的答案。你能检查一下它是否适合你吗?
    【解决方案8】:

    感谢 Mvj 解决问题!只是想我也会在时间选择器的分隔符上展示我对您的解决方案的实现。

        TimePickerDialog ptd = new TimePickerDialog(getActivity(), R.style.PickerStyler, this, hour, minute,DateFormat.is24HourFormat(getActivity()));
        ptd.setTitle("");
    
        //Needs to be try catched
        Field mTimePickerField = ptd.getClass().getDeclaredField("mTimePicker");
        mTimePickerField.setAccessible(true);
        TimePicker mTimePickerInstance = (TimePicker) mTimePickerField.get(ptd);    
    
        LinearLayout llFirst = (LinearLayout) mTimePickerInstance.getChildAt(0);
        LinearLayout llSecond = (LinearLayout) llFirst.getChildAt(0);
        boolean continiue = false;
        NumberPicker picker = null;
        for (int i = 0; i < llSecond.getChildCount(); i++) {            
            continiue = true;
            try{picker = (NumberPicker) llSecond.getChildAt(i);
                }catch(Exception e){continiue = false;}
    
            if(continiue){
                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;
                    }
                }
            }
        }   
    

    【讨论】:

    • 它没有设置 am/pm 字段的分隔符,知道为什么吗?只有前 2 个字段的分隔符被设置为不同的颜色。
    • 其实没有,抱歉。这是以 KitKat 为目标制作的。你的操作系统版本是多少?也许这已经过时了
    • 也许pickerField的名字不是mSelectionDivider。
    • 请参阅我在下面发布的解决方案。实际上,第三个字段(上午/下午)不是时间选择器,而是 NumberPicker.CustomEditText,因此上述将类型转换为 timePicker 的方法失败了,请参阅下面的另一种方法,如果你觉得它有用,请告诉我.它适用于所有版本。
    • 不适用于 28+ API。 developer.android.com/about/versions/10/non-sdk-q?authuser=1
    猜你喜欢
    • 1970-01-01
    • 2013-06-23
    • 2013-02-22
    • 1970-01-01
    • 2015-04-28
    • 1970-01-01
    • 2021-10-01
    • 1970-01-01
    • 2013-09-19
    相关资源
    最近更新 更多