一、类结构
不管怎样,先把类的继承关系搞清楚。可以上去下边的网址上查看。
DatePickerDialog 类结构:
public class
DatePickerDialog
extends AlertDialog
implements DialogInterface.OnClickListener DatePicker.OnDateChangedListener
java.lang.Object
↳ android.app.Dialog
↳ android.app.AlertDialog
↳ android.app.DatePickerDialog
通过以上,我们可以发现,DatePickerDialog实现了OnClickListener和OnDateChangedListener这两个接口。不难猜测,我们在该控件上的一些操作,可以被这两个接口监听到,并完成一些诸如日期读取的动作。
二、简单使用
DatePickerDialog的简单使用,代码如下:
DatePickerDialog picker = new DatePickerDialog(this, new OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year,
int monthOfYear, int dayOfMonth) {
// TODO Auto-generated method stub
//这里获取日期
}
}, 2016, 8, 24);
picker.show();
当对话框显现出来,是这样的:中间可手动修改日期值,也可拖动以改变日期值。
我们发现,对话框中间显现的时间,是我们上边在构造函数中传入的三个参数,2016、8、24.既然值是手动设置的,那么我们可以将其设为当前日期,在参数位置依次传入
Calendar.getInstance().get(Calendar.YEAR),
Calendar.getInstance().get(Calendar.MONTH),
Calendar.getInstance().get(Calendar.DATE)
这样,对话框显示的,就是当前日期了。
三、使用时出现的问题
首先,要注意一点,在编程语言中,很多计数,都是从0开始的,Android也不例外。日期是比较特殊的,因为没有0月一说,又,计数是从0开始的,所以,代码中所能设置的有效月份,范围是从0-11,分别代表了1-12月份。
1. 点击dialog以外空白部分,dialog消失,onDateSet仍执行了?
有这样一个需求:点击按钮出现日期选择对话框,选择完成后,点击确定,将所选日期,显示在界面上。刚做的时候,写了类似上边的代码,具体如下:
DatePickerDialog picker = new DatePickerDialog(this,
new OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year,
int monthOfYear, int dayOfMonth) {
// TODO Auto-generated method stub
monthOfYear += 1;
date_tv.setText(year + "-" + monthOfYear + "-"
+ dayOfMonth);
}
}, Calendar.getInstance().get(Calendar.YEAR), Calendar
.getInstance().get(Calendar.MONTH), Calendar
.getInstance().get(Calendar.DATE));
picker.show();
使用过程中,发现,当我点击dialog以外的地方,dialog消失,textview上却仍然显示了dialog中间的日期值。也就是说,虽然我没有点击完成按钮,onDateSet仍然执行了。
我们在所实现的onDateSet中,做一些输出,以确定onDateSet执行了。我们发现,虽然我们并没有点击“完成”按钮,但是,输出了,onDateSet确实执行了。
之前有一个习惯性思维,以为只要没有点击“完成”、“确定”等按钮,相应的事件是不能被触发的。
那么,在我没有点击“完成”的情况下,onDateSet为什么执行了呢?
2. 在dialog上添加了两个按钮ok、cancel,其OnclickListener与onDateSet执行的先后顺序?
有时候,要求在dialog上,有一个确定、一个取消俩按钮。那么,我们可以这样做:
picker.setButton(DialogInterface.BUTTON_POSITIVE, "OK",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
picker.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
出来的样式,是这样的:
然后,我习惯性地认为,onClick后于onDateSet执行。以为,在控件上选择好了日期后,点击ok按钮,我在onDateSet中得到的值,在onClick中可以直接使用了。代码如下;
private String date;
@Override
public void onDateSet(DatePicker view, int year,
int monthOfYear, int dayOfMonth) {
// TODO Auto-generated method stub
monthOfYear += 1;
date = year + "-" + monthOfYear + "-"+ dayOfMonth;
}
picker.setButton(DialogInterface.BUTTON_POSITIVE, "OK",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
System.out.println(date);
}
});
这样点击ok之后,我们可以发现,其实date中是没有值的。
那么,setButton后,其onClick与onDateSet的执行的先后顺序,是怎样的呢?
四、源码探究
通过查阅源码,可以发现,
private final OnDateSetListener mCallBack;
/**
* The callback used to indicate the user is done filling in the date.
*/
public interface OnDateSetListener {
/**
* @param view The view associated with this listener.
* @param year The year that was set.
* @param monthOfYear The month that was set (0-11) for compatibility
* with {@link java.util.Calendar}.
* @param dayOfMonth The day of the month that was set.
*/
void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth);
}
mCallBack只在这个函数中调用,
private void tryNotifyDateSet() {
if (mCallBack != null) {
mDatePicker.clearFocus();
mCallBack.onDateSet(mDatePicker, mDatePicker.getYear(),
mDatePicker.getMonth(), mDatePicker.getDayOfMonth());
}
}
而tryNotifyDateSet()只在两个地方调用,
@Override
protected void onStop() {
tryNotifyDateSet();
super.onStop();
}
public void onClick(DialogInterface dialog, int which) {
tryNotifyDateSet();
}
这样,不难看出,onDateSet()在dialog消失时,调用了一次,在onClick中,也调用了一次。
五、解决问题
这样,上面出现的两个问题,就很好解决了。
问题1:在我没有点击“完成”的情况下,onDateSet为什么执行了呢?
解决:原因是,DatePickerDialog消失后,会调用onStop(),而在onStop()中,执行了tryNotifyDateSet(),在tryNotifyDateSet()中,又调用了onDateSet。所以,无论我们如何操作,最终,都会调用onDateSet。
问题2:setButton后,onClick与onDateSet的执行的先后顺序,是怎样的呢?
解决:点击Button后,首先调用的是我们实现的onClick(),其次,在dialog消失后,调用onDateSet()。
实验
其实还有一个简单粗暴有效的实验方法,来佐证。我们可以自定义一个IDatePickerDialog,代码照搬DatePickerDialog源码,将其中一些小错误修正后,就可以随便折腾啦~