Android之界面Android

Android DatePicker遇到的那些坑

2019-07-01  本文已影响0人  惟吾德馨_慧

前言
最近遇到一个项目,需要用到时间选择器,之前图简单,直接沿用了同事的wheelView,把可选的时间以列表的形式加载到wheelView,实现xxxx年xx月是不成问题的, 但是当我们要选择xxxx年xx月xx日时就麻烦了,月有大小月之分,年有平年闰年之分,对于每月有几天的计算还是麻烦的,所以决定弃用wheelView,用Android自带的DatePicker,在选择日期上简单方便。

接下来,进入正题,DatePicker如何自定义,如何私人定制为项目需求所用?

1.DatePicker只显示年月的选择

参考文章:https://www.cnblogs.com/ivan-aldrich/p/4227439.html
在网上找了一顿资料,终于实现了隐藏DatePicker中day的显示,通过反射的方法改变DatePicker的显示
来看代码:
选择年月的DatePicker

    <DatePicker
        android:id="@+id/datePicker4YM"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:calendarViewShown="false"      //是否显示日历视图
        android:datePickerMode="spinner"        //显示为spinner视图
        android:spinnersShown="true" />           //是否显示为上下滑动样式

通过反射隐藏控件中的day

 /**
     * 隐藏时间控件中的日期选择,只显示控件中的年、月
     *
     * @param mDatePicker
     */
    private static void hideDay(DatePicker mDatePicker) {
        try {
            /* 处理android5.0以上的特殊情况 */
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                int daySpinnerId = Resources.getSystem().getIdentifier("day", "id", "android");
                if (daySpinnerId != 0) {
                    View daySpinner = mDatePicker.findViewById(daySpinnerId);
                    if (daySpinner != null) {
                        daySpinner.setVisibility(View.GONE);
                    }
                }
            } else {
                Field[] datePickerfFields = mDatePicker.getClass().getDeclaredFields();
                for (Field datePickerField : datePickerfFields) {
                    if ("mDaySpinner".equals(datePickerField.getName()) || ("mDayPicker").equals(datePickerField.getName())) {
                        datePickerField.setAccessible(true);
                        Object dayPicker = new Object();
                        try {
                            dayPicker = datePickerField.get(mDatePicker);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (IllegalArgumentException e) {
                            e.printStackTrace();
                        }
                        ((View) dayPicker).setVisibility(View.GONE);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

调用

DatePicker datePicker4YM =  findViewById(R.id.datePicker4YM);
hideDay(datePicker4YM); //按月选择,控件隐藏日期的显示
**需要注意的是,在4.0以前,DatePicker中控件的名字是mDayPicker/mMonthPicker/mYearPicker。
在4.0之后才改成了mDayspinner/mMonthSpinner/mYearSpinner.**

2.设置OnDateChangedListener事件

用过DatePicker的同学都知道,DatePicker是可以直接调用自己方法OnDateChangedListener,但是和DatePickerDialog不同的是,DatePicker直接调用自己方法OnDateChangedListener是有Android版本限制的


版本要求高,低版本不适用
//AS提示的错误信息
Call requires API level 26 (current min is 21): android.widget.DatePicker#setOnDateChangedListener less... 

解决办法:
选择年月日的DatePicker

 <DatePicker
        android:id="@+id/datePicker4Day"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:calendarViewShown="false" />

设置OnDateChangedListener事件

 int year = calendar.get(Calendar.YEAR);
 int month = calendar.get(Calendar.MONTH);
 int day = calendar.get(Calendar.DAY_OF_MONTH);

DatePicker datePicker4Day = findViewById(R.id.datePicker4Day);
datePicker4Day.init(year, month, day, new DatePicker.OnDateChangedListener() {
            @Override
            public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
                monthOfYear = monthOfYear + 1;
                String selectedDay = year + "-" + (monthOfYear < 10 ? "0" + monthOfYear : monthOfYear) + "-" 
                        + (dayOfMonth < 10 ? "0" + dayOfMonth : dayOfMonth);
                Log.i("onDateChanged", selectedDay);             
            }
        });

DatePicker设置OnDateChangedListener事件需要通过

/**
     * Initialize the state. If the provided values designate an inconsistent
     * date the values are normalized before updating the spinners.
     *
     * @param year The initial year.
     * @param monthOfYear The initial month <strong>starting from zero</strong>.
     * @param dayOfMonth The initial day of the month.
     * @param onDateChangedListener How user is notified date is changed by
     *            user, can be null.
     */
    public void init(int year, int monthOfYear, int dayOfMonth,
                     OnDateChangedListener onDateChangedListener) {
        mDelegate.init(year, monthOfYear, dayOfMonth, onDateChangedListener);
    }

方法设置,传入时间选择器的默认年月日,这样的设置方法同样适用于上面的隐藏日选择的DatePicker。

总结

有些原生控件已经足够强大,可以满足项目需求,但是由于控件的强大,需要在原来基础上改动,于是用到反射原理巧妙地修改控件的配置。还有因为Android版本的限制,一些方法不能正常使用,但是不能排除有其他方法也能同样实现效果。不拘束于开发的条条框框,跳出固定思维终能解决问题!

每天进步一点点。。。(2019-07-01)

上一篇下一篇

猜你喜欢

热点阅读