setMaxDate()在Android Lollipop 5.0.1上无法完美运行,需要适当的解决方案。

12
即使在日期选择器上应用了 setMaxDate() 方法,我仍然能够在安卓5.0.1上选择被禁用的日期。除了安卓5.0.1之外,该代码对其他所有安卓版本都有效。
在使用 setMaxDate() 对日期做出限制后,任何用户都不应该能够选择被禁用的日期。我该如何通过编程方式实现这一点并应用于 DatePicker 组件?
我已经尝试过以下代码:
datePickerDialog = new DatePickerDialog(myContext, new DatePickerDialog.OnDateSetListener() {
        @Override
        public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
        }
    }, mYear, mMonth, mDay);
    datePickerDialog.getDatePicker().setMaxDate(System.currentTimeMillis());
    datePickerDialog.setCanceledOnTouchOutside(true);
    datePickerDialog.setCancelable(true);
    datePickerDialog.show();

我也尝试过以下解决方案,但似乎都无法解决问题:

datePickerDialog.getDatePicker().setMaxDate(System.currentTimeMillis());

Calendar maxCal = Calendar.getInstance();
datePickerDialog.getDatePicker().setMaxDate(maxCal.getTimeInMillis());

Date maxDate = new Date();
datePickerDialog.getDatePicker().setMaxDate(maxDate.getTime());
请提供适用于Lollipop版本的setMaxDate()的解决方案。如果您有其他答案,请尽量包含官方引用、资源或链接(如Android开发者网站),并简要说明。谢谢。

你能提一下设备制造商的名字吗? - Rahul Khurana
@Opiatefuchs 我不认为它是长整型。此外,我已经提到它在其他版本中运行良好。 - Nitin Patel
如果您有时间并且可能的话,请尝试检查它,并在发现问题时提供解决方案。顺便说一下,谢谢。 - Nitin Patel
棒棒糖5.0的DatePickerDialog存在缺陷:https://issuetracker.google.com/issues/37018603,来源于这里:https://dev59.com/oFwY5IYBdhLWcg3wEER2#33051501。 - nandsito
1
不要试图让它工作。DatePicker 在每个设备和 Android 版本中都会有所不同,有些会显示禁用的日期,而有些仍然可以选择它们,还有一些则完全忽略这些设置。请确保检查返回的值,并/或切换到其他库(谷歌/ GitHub 搜索)。来源:已经浪费了足够多的时间在这上面。 - David Medenjak
显示剩余6条评论
3个回答

6

正如评论中指出的那样,对于这个有缺陷的日历(在Android 5.0上可以选择无效日期,在某些三星设备上存在奇怪的行为:按下返回按钮实际上选择了一个日期,还有其他我不太记得的问题),真正没有完美的解决方案。但是,我通过检查无效日期的有效性并在失败的情况下显示一个Toast来解决了选择无效日期的问题。这并不能阻止用户实际上选择无效日期,而是强制用户选择有效日期以继续使用应用程序。

   DatePickerDialog dialog = new DatePickerDialog(getActivity(), mOnDateSetListener, year, month, day) {
        private boolean allowClose = false;

        @Override
        public void onBackPressed() {
            allowClose = true;
            super.onBackPressed();
        }

        @Override
        public void onClick(DialogInterface dialog, int which) {
            allowClose = true;
            if (which == DialogInterface.BUTTON_POSITIVE && !validate()) {
                allowClose = false;
                Toast.makeText(getContext(), R.string.invalid_date, Toast.LENGTH_SHORT).show();
            }
            if (allowClose) {
                super.onClick(dialog, which);
            }
        }

        @Override
        public void dismiss() {
            if (allowClose) {
                super.dismiss();
            }
        }
    };

使用这个方法,您可以确保如果用户选择了无效的日期,您将向他提供适当的警告信息,并在按下“确定”按钮时停止日历关闭。 validate函数应根据您的需求进行创建,但我认为我所提供的内容已经足够:

private boolean validate() {
    if (this.getDialog() instanceof DatePickerDialog) {
        DatePicker datePicker = ((DatePickerDialog) this.getDialog()).getDatePicker();
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, datePicker.getYear());
        calendar.set(Calendar.MONTH, datePicker.getMonth());
        calendar.set(Calendar.DAY_OF_MONTH, datePicker.getDayOfMonth());
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        boolean valid = false;
        Calendar minCalendar = Calendar.getInstance();
        minCalendar.setTimeInMillis(datePicker.getMinDate());
        Calendar maxCalendar = Calendar.getInstance();
        maxCalendar.setTimeInMillis(datePicker.getMaxDate());
        if (DateUtils.in(calendar.getTime(), minCalendar.getTime(), maxCalendar.getTime())) {
            valid = true;
        }
        return valid;
    }
    return false;
}

作为最后的一句话,我不能保证这是最好的解决方案,但我已经使用过它,并且没有收到任何用户的投诉。

感谢您的建议。我知道并已经尝试过了。如果可能的话,需要解决方案而不是其他方式来满足要求。 - Nitin Patel
也许你可以通过子类化DatePicker来实现你想要的效果,但我需要进一步调查。在我有时间尝试子类化版本之前,我会把它留在这里。 - Iulian Popescu

3

我已经找到了一个关于日期选择器的库,名为wdullaer/MaterialDateTimePicker。该库在Android 5.0.1 Lollipop上运行完美,并且与其他API版本一样可用。

您可以通过以下链接获取解决方案库:点击此处以获取MaterialDateTimePicker

将以下代码添加到build.gradle(app)文件中的dependencies{...}中即可引入此库。

compile 'com.wdullaer:materialdatetimepicker:3.2.1'

根据需要实现以下代码:

MainActivity mainActivity = (MainActivity) myContext;
    final DatePickerDialog dpd = DatePickerDialog.newInstance(
            new DatePickerDialog.OnDateSetListener() {
                @Override
                public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) {
                    //To do your task here
                }
            },
            mYear,
            mMonth,
            mDay
    );
    dpd.setVersion(DatePickerDialog.Version.VERSION_2);
    dpd.setMaxDate(Calendar.getInstance());
    dpd.show(mainActivity.getFragmentManager(), "Datepickerdialog");

2
您需要添加日历实例并将其用作maxDate。请参考以下代码中添加的行。
datePickerDialog = new DatePickerDialog(myContext, new DatePickerDialog.OnDateSetListener() {
    @Override
    public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
    }
}, mYear, mMonth, mDay);

Calendar maxCal = Calendar.getInstance();

datePickerDialog.getDatePicker().setMaxDate(maxCal.getTimeInMillis());
datePickerDialog.setCanceledOnTouchOutside(true);
datePickerDialog.setCancelable(true);
datePickerDialog.show();

无法工作。您能否在您的端上检查一下,这是否适用于棒棒糖版本? - Nitin Patel
是的,它适用于棒棒糖版本。已经检查过了。您仍然可以使用此代码选择大于今天的日期吗? - SilverSky
是的,我能够选择大于今天的日期。而且我有一台安装了Lollipop 5.0.1的真实设备。 - Nitin Patel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接