上的DatePicker设置为MinDate移动CalendarView至1964年 [英] Setting MinDate on DatePicker moves CalendarView to 1964

查看:269
本文介绍了上的DatePicker设置为MinDate移动CalendarView至1964年的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我调试一个问题,即 CalendarView 的DatePicker 移动到1964年10月,如果有一个非 - 默认最小日期集。该再现至少在API17 Nexus7仿真器,但也有这个问题上的其他设备,其中该平台的风格包括纺纱和日历视图,日期选取器报告。

I'm debugging an issue where the CalendarView in a DatePicker moves to October 1964 if there is a non-default minimum date set. This reproduces at least on API17 Nexus7 emulator but there are reports about this issue on other devices where the platform style includes both spinners and calendar view in date picker.

下面是一个code片段演示了这个问题:

Here's a code snippet demonstrating the issue:

class DatePickerDialog1964 extends DatePickerDialog {
    DatePickerDialog1964(Context c) {
        super(c, null, 2013, 4, 21);

        @SuppressWarnings("deprecation")
        Date min = new Date(2013-1900, 4, 21);

        DatePicker p = getDatePicker();
        p.setMinDate(min.getTime());
    }
}

...

new DatePickerDialog1964(context).show();

截屏:

当然,期望的是,纺织和日历视图将显示相同的日期。

Of course, the expectation is that the spinners and calendar view would be showing the same date.

我会继续调试这一点,但如果有的话,以便用户有经验或其他见解,欢迎交流。

I'll keep on debugging this but if any SO users have experience or other insight, please share.

相关报道:

  • Issue 42750: CalendarView initially scrolls to year 1964
  • using CalendarView to pick a date in future (android-developers)

推荐答案

这不是1964年而是2100格式化严重。 CalendarView 有缺陷。 formatDateRange()不起作用过去的2038。

TL;DR

It's not 1964 but 2100 formatted badly. CalendarView has bugs. formatDateRange() does not work past 2038.

class DatePickerDialog1964 extends DatePickerDialog {
    DatePickerDialog1964(Context c) {
        super(c, null, 2013, 4, 21);

        @SuppressWarnings("deprecation")
        Date min = new Date(2013-1900, 4, 21);

        DatePicker p = getDatePicker();
        CalendarView cv = p.getCalendarView(); // should check for null
        long cur = cv.getDate();
        int d = cv.getFirstDayOfWeek();
        p.setMinDate(min.getTime());
        cv.setDate(cur + 1000L*60*60*24*40);
        cv.setFirstDayOfWeek((d + 1) % 7);
        cv.setDate(cur);
        cv.setFirstDayOfWeek(d);
    }
}

解决方法#2我实际使用

// Calendar view is a cascade of bugs.
// Work around that by explicitly disabling it.
datePicker.setCalendarViewShown(false);

分析

CalendarView 使用 android.text.format.DateUtils.formatDateRange()生产在月/年的名字的报头。日历视图只更新头球时月号的变化。例如,如果月数是相同的,但年变化,首标不被更新。

Analysis

CalendarView uses android.text.format.DateUtils.formatDateRange() for producing the month/year name in the header. Calendar view only updates the header when the month number changes. For example, if the month number is the same but the year changes, the header is not updated.

在布局阶段,潜在的的ListView 调用 OnScrollListener 上的日历视图某处,如果列表中已滚动至最后。如果该月数发生变化时,头部与测试code以上更新,传递给 formatDateRange()的米利斯值 4131043200000 这是在2100年下旬的某个地方,和2100是默认的最大值的DatePicker

Somewhere during layout phase, the underlying ListView invokes OnScrollListener on the calendar view as if the list was scrolled to the end. If the month number is changed, the header is updated with the test code above, the millis value passed to formatDateRange() is 4131043200000 which is somewhere in late 2100, and 2100 is the default maximum for DatePicker.

formatDateRange()又使用 android.text.format.Time 作为其内部日历再presentation,专门设置使用其设置()方法米利斯。我没有检查底层本地code,但我的猜测是,以毫秒为单位值传递被截断为32位 time_t的秒值和固有的<一个HREF =htt​​p://en.wikipedia.org/wiki/Year_2038_problem> 2038年问题,包装到有点超过62年的价值。 时间本身是使用结构TM 从而重新presents年的 INT 自1900年以来,这样就造成了时间 20世纪60年代,然后被在头格式。

formatDateRange() in turn uses android.text.format.Time as its internal calendar representation, specifically setting the millis using its set() method. I did not check the underlying native code, but my educated guess is that the passed in milliseconds value gets truncated to 32-bit time_t seconds value with the inherent Year 2038 problem, wrapping to a value of a little more than 62 years. Time itself is using struct tm which represents years as an int since 1900, thus resulting in a Time in the 1960s which then gets formatted in the header.

这可以进行复制,平原的DatePicker CalendarView 无分设定日期。只需使用微调器今年移动到2038或更高版本,更改月份(触发标题更新),你会看到头包年至1902年。

This can be reproduced with plain DatePicker with CalendarView without min date set. Just use the spinners to move the year to 2038 or later, change the month (to trigger the header update) and you'll see the year in header wrap to 1902.

现在,问题是,为什么设定一个最小日期,使日历视图滚动到最大日期。答案似乎是日历视图中的周的ListView 适配器。该指数周从最小日期,但在最小日期改变,适配器的 notifyDataSetChanged()不叫。因此,解决方法#1以上的工作,因为:

Now, the question remains why setting a minimum date makes the calendar view scroll to maximum date. Answer seems to be the calendar view's week ListView adapter. It indexes weeks from the minimum date, but when the minimum date changes, the adapter's notifyDataSetChanged() is not called. So the workaround #1 above works because:

  • 更改日期一个多月使得本月头的变化。
  • 更改每周的第一天,使星期列表视图注意到它的适配器的数据发生了变化。

这篇关于上的DatePicker设置为MinDate移动CalendarView至1964年的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆