关闭

DatePickerDialog初次使用,所遇到的一些坑

39人阅读 评论(0) 收藏 举报
分类:

一、类结构

不管怎样,先把类的继承关系搞清楚。可以上去下边的网址上查看。

http://www.android-doc.com/reference/packages.html

DatePickerDialog 类结构:

public class
DatePickerDialog
extends AlertDialog
implements DialogInterface.OnClickListener DatePicker.OnDateChangedListener
java.lang.Objectandroid.app.Dialogandroid.app.AlertDialogandroid.app.DatePickerDialog

通过以上,我们可以发现,DatePickerDialog实现了OnClickListenerOnDateChangedListener这两个接口。不难猜测,我们在该控件上的一些操作,可以被这两个接口监听到,并完成一些诸如日期读取的动作。

二、简单使用

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源码,将其中一些小错误修正后,就可以随便折腾啦~

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:183次
    • 积分:42
    • 等级:
    • 排名:千里之外
    • 原创:3篇
    • 转载:1篇
    • 译文:0篇
    • 评论:0条
    文章存档