Skip to content

Commit

Permalink
Allow overriding calculateExtraLayoutSpace in the layout manager (#601
Browse files Browse the repository at this point in the history
)
  • Loading branch information
kizitonwose authored Jan 14, 2025
1 parent 0e1b654 commit aea1992
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 7 deletions.
14 changes: 14 additions & 0 deletions view/api/view.api
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class com/kizitonwose/calendar/view/CalendarView : androidx/recyclerview/
public final fun getDayBinder ()Lcom/kizitonwose/calendar/view/MonthDayBinder;
public final fun getDaySize ()Lcom/kizitonwose/calendar/view/DaySize;
public final fun getDayViewResource ()I
public final fun getLayoutHelper ()Lcom/kizitonwose/calendar/view/LayoutHelper;
public final fun getMonthFooterBinder ()Lcom/kizitonwose/calendar/view/MonthHeaderFooterBinder;
public final fun getMonthFooterResource ()I
public final fun getMonthHeaderBinder ()Lcom/kizitonwose/calendar/view/MonthHeaderFooterBinder;
Expand All @@ -39,6 +40,7 @@ public class com/kizitonwose/calendar/view/CalendarView : androidx/recyclerview/
public final fun setDayBinder (Lcom/kizitonwose/calendar/view/MonthDayBinder;)V
public final fun setDaySize (Lcom/kizitonwose/calendar/view/DaySize;)V
public final fun setDayViewResource (I)V
public final fun setLayoutHelper (Lcom/kizitonwose/calendar/view/LayoutHelper;)V
public final fun setMonthFooterBinder (Lcom/kizitonwose/calendar/view/MonthHeaderFooterBinder;)V
public final fun setMonthFooterResource (I)V
public final fun setMonthHeaderBinder (Lcom/kizitonwose/calendar/view/MonthHeaderFooterBinder;)V
Expand Down Expand Up @@ -72,6 +74,14 @@ public final class com/kizitonwose/calendar/view/DaySize : java/lang/Enum {
public static fun values ()[Lcom/kizitonwose/calendar/view/DaySize;
}

public abstract interface class com/kizitonwose/calendar/view/LayoutHelper {
public abstract fun calculateExtraLayoutSpace (Landroidx/recyclerview/widget/RecyclerView$State;[I)V
}

public final class com/kizitonwose/calendar/view/LayoutHelper$DefaultImpls {
public static fun calculateExtraLayoutSpace (Lcom/kizitonwose/calendar/view/LayoutHelper;Landroidx/recyclerview/widget/RecyclerView$State;[I)V
}

public final class com/kizitonwose/calendar/view/MarginValues {
public static final field Companion Lcom/kizitonwose/calendar/view/MarginValues$Companion;
public fun <init> ()V
Expand Down Expand Up @@ -128,6 +138,7 @@ public class com/kizitonwose/calendar/view/WeekCalendarView : androidx/recyclerv
public final fun getDayBinder ()Lcom/kizitonwose/calendar/view/WeekDayBinder;
public final fun getDaySize ()Lcom/kizitonwose/calendar/view/DaySize;
public final fun getDayViewResource ()I
public final fun getLayoutHelper ()Lcom/kizitonwose/calendar/view/LayoutHelper;
public final fun getScrollPaged ()Z
public final fun getWeekFooterBinder ()Lcom/kizitonwose/calendar/view/WeekHeaderFooterBinder;
public final fun getWeekFooterResource ()I
Expand All @@ -148,6 +159,7 @@ public class com/kizitonwose/calendar/view/WeekCalendarView : androidx/recyclerv
public final fun setDayBinder (Lcom/kizitonwose/calendar/view/WeekDayBinder;)V
public final fun setDaySize (Lcom/kizitonwose/calendar/view/DaySize;)V
public final fun setDayViewResource (I)V
public final fun setLayoutHelper (Lcom/kizitonwose/calendar/view/LayoutHelper;)V
public final fun setScrollPaged (Z)V
public final fun setWeekFooterBinder (Lcom/kizitonwose/calendar/view/WeekHeaderFooterBinder;)V
public final fun setWeekFooterResource (I)V
Expand Down Expand Up @@ -187,6 +199,7 @@ public class com/kizitonwose/calendar/view/YearCalendarView : androidx/recyclerv
public final fun getDayBinder ()Lcom/kizitonwose/calendar/view/MonthDayBinder;
public final fun getDaySize ()Lcom/kizitonwose/calendar/view/DaySize;
public final fun getDayViewResource ()I
public final fun getLayoutHelper ()Lcom/kizitonwose/calendar/view/LayoutHelper;
public final fun getMonthColumns ()I
public final fun getMonthFooterBinder ()Lcom/kizitonwose/calendar/view/MonthHeaderFooterBinder;
public final fun getMonthFooterResource ()I
Expand Down Expand Up @@ -225,6 +238,7 @@ public class com/kizitonwose/calendar/view/YearCalendarView : androidx/recyclerv
public final fun setDayBinder (Lcom/kizitonwose/calendar/view/MonthDayBinder;)V
public final fun setDaySize (Lcom/kizitonwose/calendar/view/DaySize;)V
public final fun setDayViewResource (I)V
public final fun setLayoutHelper (Lcom/kizitonwose/calendar/view/LayoutHelper;)V
public final fun setMonthColumns (I)V
public final fun setMonthFooterBinder (Lcom/kizitonwose/calendar/view/MonthHeaderFooterBinder;)V
public final fun setMonthFooterResource (I)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@ public open class CalendarView : RecyclerView {
}
}

/**
* Interface with methods that can be overridden
* in the internal layout manager.
*/
public var layoutHelper: LayoutHelper? = null

private val scrollListenerInternal = object : OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {}
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
Expand Down
22 changes: 22 additions & 0 deletions view/src/main/java/com/kizitonwose/calendar/view/LayoutHelper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.kizitonwose.calendar.view

import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.kizitonwose.calendar.view.internal.CalendarLayoutManager

/**
* An interface with methods that can be overridden
* in the internal [LinearLayoutManager].
*/
public interface LayoutHelper {
/**
* Calculates the amount of extra space (in pixels) that should be laid out by
* [CalendarLayoutManager] and stores the result in [extraLayoutSpace].
* [extraLayoutSpace[0]] should be used for the extra space at the top in a vertical
* calendar or left in a horizontal calendar, and extraLayoutSpace[1] should be used for
* the extra space at the bottom in a vertical calendar or right in a horizontal calendar.
*
* @see [LinearLayoutManager.calculateExtraLayoutSpace]
*/
public fun calculateExtraLayoutSpace(state: RecyclerView.State, extraLayoutSpace: IntArray) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,12 @@ public open class WeekCalendarView : RecyclerView {
}
}

/**
* Interface with methods that can be overridden
* in the internal layout manager.
*/
public var layoutHelper: LayoutHelper? = null

private val scrollListenerInternal = object : OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {}
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,12 @@ public open class YearCalendarView : RecyclerView {
}
}

/**
* Interface with methods that can be overridden
* in the internal layout manager.
*/
public var layoutHelper: LayoutHelper? = null

private val scrollListenerInternal = object : OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {}
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView
import com.kizitonwose.calendar.view.LayoutHelper
import com.kizitonwose.calendar.view.MarginValues

internal abstract class CalendarLayoutManager<IndexData, DayData>(
Expand All @@ -18,6 +19,7 @@ internal abstract class CalendarLayoutManager<IndexData, DayData>(
abstract fun getItemMargins(): MarginValues
abstract fun scrollPaged(): Boolean
abstract fun notifyScrollListenerIfNeeded()
abstract fun getLayoutHelper(): LayoutHelper?

fun scrollToIndex(indexData: IndexData) {
val position = getaItemAdapterPosition(indexData)
Expand Down Expand Up @@ -70,6 +72,19 @@ internal abstract class CalendarLayoutManager<IndexData, DayData>(
}
}

override fun calculateExtraLayoutSpace(state: RecyclerView.State, extraLayoutSpace: IntArray) {
val layoutHelper = getLayoutHelper()
if (layoutHelper != null) {
layoutHelper.calculateExtraLayoutSpace(state, extraLayoutSpace)
// If the interface is provided but the method is not overridden.
if (extraLayoutSpace.isEmpty()) {
super.calculateExtraLayoutSpace(state, extraLayoutSpace)
}
} else {
super.calculateExtraLayoutSpace(state, extraLayoutSpace)
}
}

private inner class CalendarSmoothScroller(position: Int, val day: DayData?) :
LinearSmoothScroller(calView.context) {
init {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.kizitonwose.calendar.view.internal.monthcalendar

import com.kizitonwose.calendar.core.CalendarDay
import com.kizitonwose.calendar.view.CalendarView
import com.kizitonwose.calendar.view.LayoutHelper
import com.kizitonwose.calendar.view.MarginValues
import com.kizitonwose.calendar.view.internal.CalendarLayoutManager
import com.kizitonwose.calendar.view.internal.dayTag
Expand All @@ -18,4 +19,5 @@ internal class MonthCalendarLayoutManager(private val calView: CalendarView) :
override fun getItemMargins(): MarginValues = calView.monthMargins
override fun scrollPaged(): Boolean = calView.scrollPaged
override fun notifyScrollListenerIfNeeded() = adapter.notifyMonthScrollListenerIfNeeded()
override fun getLayoutHelper(): LayoutHelper? = calView.layoutHelper
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.kizitonwose.calendar.view.internal.weekcalendar

import com.kizitonwose.calendar.view.LayoutHelper
import com.kizitonwose.calendar.view.MarginValues
import com.kizitonwose.calendar.view.WeekCalendarView
import com.kizitonwose.calendar.view.internal.CalendarLayoutManager
Expand All @@ -17,4 +18,5 @@ internal class WeekCalendarLayoutManager(private val calView: WeekCalendarView)
override fun getItemMargins(): MarginValues = calView.weekMargins
override fun scrollPaged(): Boolean = calView.scrollPaged
override fun notifyScrollListenerIfNeeded() = adapter.notifyWeekScrollListenerIfNeeded()
override fun getLayoutHelper(): LayoutHelper? = calView.layoutHelper
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearSmoothScroller
import com.kizitonwose.calendar.core.CalendarDay
import com.kizitonwose.calendar.view.LayoutHelper
import com.kizitonwose.calendar.view.MarginValues
import com.kizitonwose.calendar.view.YearCalendarView
import com.kizitonwose.calendar.view.internal.CalendarLayoutManager
Expand All @@ -24,6 +25,8 @@ internal class YearCalendarLayoutManager(private val calView: YearCalendarView)
override fun getItemMargins(): MarginValues = calView.yearMargins
override fun scrollPaged(): Boolean = calView.scrollPaged
override fun notifyScrollListenerIfNeeded() = adapter.notifyYearScrollListenerIfNeeded()
override fun getLayoutHelper(): LayoutHelper? = calView.layoutHelper

fun smoothScrollToMonth(month: YearMonth) {
val indexPosition = adapter.getAdapterPosition(month)
if (indexPosition == NO_INDEX) return
Expand All @@ -42,18 +45,18 @@ internal class YearCalendarLayoutManager(private val calView: YearCalendarView)
calView.post {
val itemView = calView.findViewHolderForAdapterPosition(indexPosition)?.itemView
?: return@post
val offset = calculateDayViewOffsetInParent(month, itemView)
val offset = calculateMonthViewOffsetInParent(month, itemView)
scrollToPositionWithOffset(indexPosition, -offset)
calView.post { notifyScrollListenerIfNeeded() }
}
}
}

private fun calculateDayViewOffsetInParent(month: YearMonth, itemView: View): Int {
val dayView = itemView.findViewWithTag<View>(monthTag(month)) ?: return 0
private fun calculateMonthViewOffsetInParent(month: YearMonth, itemView: View): Int {
val monthView = itemView.findViewWithTag<View>(monthTag(month)) ?: return 0
val rect = Rect()
dayView.getDrawingRect(rect)
(itemView as ViewGroup).offsetDescendantRectToMyCoords(dayView, rect)
monthView.getDrawingRect(rect)
(itemView as ViewGroup).offsetDescendantRectToMyCoords(monthView, rect)
return if (orientation == VERTICAL) rect.top else rect.left
}

Expand All @@ -72,7 +75,7 @@ internal class YearCalendarLayoutManager(private val calView: YearCalendarView)
if (month == null) {
return dy
}
val offset = calculateDayViewOffsetInParent(month, view)
val offset = calculateMonthViewOffsetInParent(month, view)
return dy - offset
}

Expand All @@ -81,7 +84,7 @@ internal class YearCalendarLayoutManager(private val calView: YearCalendarView)
if (month == null) {
return dx
}
val offset = calculateDayViewOffsetInParent(month, view)
val offset = calculateMonthViewOffsetInParent(month, view)
return dx - offset
}
}
Expand Down

0 comments on commit aea1992

Please sign in to comment.