prolificinteractive / material-calendarview

A Material design back port of Android's CalendarView
https://prolificinteractive.github.io/material-calendarview/
MIT License
5.92k stars 1.32k forks source link

Date in Title always starts with today #1035

Open fabianbouchal opened 4 years ago

fabianbouchal commented 4 years ago

Picture the following scenario

Am I missing something here? In my opinion the header title should always be the month and year of the dates displayed below by default. It doesn't make sense to use todays month and year if a different month is displayed below.

Does anyone have an idea how I can change that or how I can override the title based on the month that is displayed in the calendar view? Any input is highly appreciated.

devrajmaker commented 4 years ago

would you please elaborate more clear

fabianbouchal commented 4 years ago

would you please elaborate more clear

Would you please elaborate what's unclear

dalewking commented 3 years ago

I've done some digging on this and can somewhat point you to the cause.

The title is updated based on currentMonth. The only thing that primarily updates currentMonth is the onPageSelected listener method that is listening to page changes from the pageAdapter which only gets called when the currentItem for the page adapter changes.

The problem is that there are things that you can do that changes the interpretation of how an index maps to a date that do not trigger the onPageSelected to be called. This primarily concerns changes in the min/max dates.

So here is a scenario that will demonstrate the problem:

The reason for this behavior is that those changes do not result in a call to onPageSelected, because the pager index in both cases is 0.

If you look at setRangeDates method, it handles the case where currentMonth is before the new minimum and moves currentMonth forward, but it does not handle the case where currentMonth is after the new maximum. The call to adapter.getIndexForDay(c) will move the pager to the correct month, but it does not update currentMonth and in the scenario I laid out the index in the pager does not change (it will be zero) so the onPageListener will not get called either to update the currentMonth since the index did not change.

I think this might be a better implementation of setRangeDates that would fix the problem:

  private void setRangeDates(CalendarDay min, CalendarDay max) {
    adapter.setRangeDates(min, max);
    int position = adapter.getIndexForDay(currentMonth);
    pager.setCurrentItem(position, false);
    pageChangeListener.onPageSelected(position);
  }
dalewking commented 3 years ago

I have implemented this hack in our Kotlin code that I call after committing the state with the modified min/max and it seems to work:

private val pageChangeListener: Field by lazy {
    MaterialCalendarView::class.java
        .getDeclaredField("pageChangeListener")
        .apply { isAccessible = true }
}

private val viewPager: Field by lazy {
    MaterialCalendarView::class.java
        .getDeclaredField("pager")
        .apply { isAccessible = true }
}

And this code called after setting date range

    // FIXME: This is work around for cases where the title is not getting updated by calendar view
    //        See https://github.com/prolificinteractive/material-calendarview/issues/1035
    (pageChangeListener.get(this) as ViewPager.OnPageChangeListener)
        .onPageSelected((viewPager.get(this) as ViewPager).currentItem)