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

一、类结构

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

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值