前言
最近遇到一个项目,需要用到时间选择器,之前图简单,直接沿用了同事的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版本的限制,一些方法不能正常使用,但是不能排除有其他方法也能同样实现效果。不拘束于开发的条条框框,跳出固定思维终能解决问题!