Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow overriding calculateExtraLayoutSpace in the layout manager #601

Merged
merged 1 commit into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading