From 71f41bb3d2a76ed1272c59f4acc3632432075be5 Mon Sep 17 00:00:00 2001 From: Marcin Simonides Date: Sat, 12 Oct 2019 17:42:21 +0200 Subject: [PATCH 1/2] Add an updateRange method. The method changes startMonth and/or endMonth with minimal updates to the underlying RecyclerView. This fixes #67. --- .../kizitonwose/calendarview/CalendarView.kt | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/library/src/main/java/com/kizitonwose/calendarview/CalendarView.kt b/library/src/main/java/com/kizitonwose/calendarview/CalendarView.kt index ff6b06e3..b3302732 100644 --- a/library/src/main/java/com/kizitonwose/calendarview/CalendarView.kt +++ b/library/src/main/java/com/kizitonwose/calendarview/CalendarView.kt @@ -5,6 +5,7 @@ import android.util.AttributeSet import android.view.View.MeasureSpec.UNSPECIFIED import android.view.ViewGroup import androidx.annotation.Px +import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.PagerSnapHelper import androidx.recyclerview.widget.RecyclerView import com.kizitonwose.calendarview.model.* @@ -12,6 +13,7 @@ import com.kizitonwose.calendarview.ui.* import com.kizitonwose.calendarview.utils.NO_INDEX import org.threeten.bp.DayOfWeek import org.threeten.bp.LocalDate +import org.threeten.bp.Period import org.threeten.bp.YearMonth @@ -581,6 +583,7 @@ open class CalendarView : RecyclerView { /** * Setup the CalendarView. You can call this any time to change the * the desired [startMonth], [endMonth] or [firstDayOfWeek] on the Calendar. + * Use the [updateRange] method when changing only the [startMonth] and [endMonth]. * * @param startMonth The first month on the calendar. * @param endMonth The last month on the calendar. @@ -619,6 +622,49 @@ open class CalendarView : RecyclerView { ) } + /** + * Update the CalendarView's month range. This method does the minimal updates to the + * underlying RecyclerView resulting in a stable view when the changes don't affect the visible + * month(s). + */ + fun updateRange(startMonth: YearMonth, endMonth: YearMonth) { + val oldStartMonth = this.startMonth!! + val oldEndMonth = this.endMonth!! + this.startMonth = startMonth + this.endMonth = endMonth + + calendarAdapter.monthConfig = + MonthConfig( + outDateStyle, inDateStyle, maxRowCount, + startMonth, endMonth, firstDayOfWeek ?: return, + hasBoundaries + ) + DiffUtil.calculateDiff( + MonthRangeDiffCallback(oldStartMonth, oldEndMonth, startMonth, endMonth), false) + .dispatchUpdatesTo(calendarAdapter) + } + + private class MonthRangeDiffCallback( + private val oldStartMonth: YearMonth, + private val oldEndMonth: YearMonth, + private val newStartMonth: YearMonth, + private val newEndMonth: YearMonth + ) : DiffUtil.Callback() { + + override fun getOldListSize() = monthCount(oldStartMonth, oldEndMonth) + + override fun getNewListSize() = monthCount(newStartMonth, newEndMonth) + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) + = oldStartMonth.plusMonths(oldItemPosition.toLong()) == newStartMonth.plusMonths(newItemPosition.toLong()) + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) + = areItemsTheSame(oldItemPosition, newItemPosition) + + private fun monthCount(a: YearMonth, b: YearMonth) = + 1 + Period.between(a.atDay(1), b.atDay(1)).months + } + companion object { /** * A value for [dayWidth] and [dayHeight] which indicates that the day From 8a3cbc714973b047471cfebbba843dadb1e189ae Mon Sep 17 00:00:00 2001 From: Marcin Simonides Date: Sat, 26 Oct 2019 10:21:59 +0200 Subject: [PATCH 2/2] fixup! Add an updateRange method. Run the diff algorithms on the "months" list to support various maxRowCounts. --- .../kizitonwose/calendarview/CalendarView.kt | 36 ++++++++----------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/library/src/main/java/com/kizitonwose/calendarview/CalendarView.kt b/library/src/main/java/com/kizitonwose/calendarview/CalendarView.kt index b3302732..cada3fe2 100644 --- a/library/src/main/java/com/kizitonwose/calendarview/CalendarView.kt +++ b/library/src/main/java/com/kizitonwose/calendarview/CalendarView.kt @@ -13,7 +13,6 @@ import com.kizitonwose.calendarview.ui.* import com.kizitonwose.calendarview.utils.NO_INDEX import org.threeten.bp.DayOfWeek import org.threeten.bp.LocalDate -import org.threeten.bp.Period import org.threeten.bp.YearMonth @@ -628,41 +627,36 @@ open class CalendarView : RecyclerView { * month(s). */ fun updateRange(startMonth: YearMonth, endMonth: YearMonth) { - val oldStartMonth = this.startMonth!! - val oldEndMonth = this.endMonth!! this.startMonth = startMonth this.endMonth = endMonth - calendarAdapter.monthConfig = - MonthConfig( - outDateStyle, inDateStyle, maxRowCount, - startMonth, endMonth, firstDayOfWeek ?: return, - hasBoundaries - ) - DiffUtil.calculateDiff( - MonthRangeDiffCallback(oldStartMonth, oldEndMonth, startMonth, endMonth), false) + val oldConfig = calendarAdapter.monthConfig + val newConfig = MonthConfig( + outDateStyle, inDateStyle, maxRowCount, + startMonth, endMonth, firstDayOfWeek ?: return, + hasBoundaries + ) + calendarAdapter.monthConfig = newConfig + + DiffUtil + .calculateDiff(MonthRangeDiffCallback(oldConfig.months, newConfig.months), false) .dispatchUpdatesTo(calendarAdapter) } private class MonthRangeDiffCallback( - private val oldStartMonth: YearMonth, - private val oldEndMonth: YearMonth, - private val newStartMonth: YearMonth, - private val newEndMonth: YearMonth + private val oldItems: List, + private val newItems: List ) : DiffUtil.Callback() { - override fun getOldListSize() = monthCount(oldStartMonth, oldEndMonth) + override fun getOldListSize() = oldItems.size - override fun getNewListSize() = monthCount(newStartMonth, newEndMonth) + override fun getNewListSize() = newItems.size override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) - = oldStartMonth.plusMonths(oldItemPosition.toLong()) == newStartMonth.plusMonths(newItemPosition.toLong()) + = oldItems[oldItemPosition] == newItems[newItemPosition] override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) = areItemsTheSame(oldItemPosition, newItemPosition) - - private fun monthCount(a: YearMonth, b: YearMonth) = - 1 + Period.between(a.atDay(1), b.atDay(1)).months } companion object {