Open mpierucci opened 5 years ago
This is talked about in #162, copying my comment from there to here:
The only way to do this still is to specify three different decorators as mentioned above (left, middle, and right) and apply/remove those as necessary. For the purposes of date range selection I feel that decorators shouldn't be used (and instead should be reserved for stuff like event dots and other such decoration). The idea of start, middle, and end range selection drawables should probably be migrated inside the library and exposed via some attributes on the view.
My current solution for this is to wrap these three decorators up in a handler that adds and removes them all as one:
class RangeSelectionDecorator(
private val leftDrawable: Drawable,
private val middleDrawable: Drawable,
private val rightDrawable: Drawable
) {
private var previousDecorators = emptyList<DayViewDecorator>()
fun clear(calendar: MaterialCalendarView) {
previousDecorators.forEach { calendar.removeDecorator(it) }
}
fun applyForSelection(calendar: MaterialCalendarView, selectedDates: List<LocalDate>) {
clear(calendar)
val newDecorators = getDecoratorsForSelection(selectedDates)
calendar.addDecorators(newDecorators)
previousDecorators = newDecorators
}
private fun getDecoratorsForSelection(selectedDates: List<LocalDate>): List<DayViewDecorator> {
val first = selectedDates.first()
val last = selectedDates.last()
val middle = selectedDates.subtract(listOf(first, last))
return listOf(
RangeSelectionLeftDecorator(first, leftDrawable),
RangeSelectionMiddleDecorator(middle, middleDrawable),
RangeSelectionRightDecorator(last, rightDrawable)
)
}
}
This is talked about in #162, copying my comment from there to here:
The only way to do this still is to specify three different decorators as mentioned above (left, middle, and right) and apply/remove those as necessary. For the purposes of date range selection I feel that decorators shouldn't be used (and instead should be reserved for stuff like event dots and other such decoration). The idea of start, middle, and end range selection drawables should probably be migrated inside the library and exposed via some attributes on the view.
My current solution for this is to wrap these three decorators up in a handler that adds and removes them all as one:
class RangeSelectionDecorator( private val leftDrawable: Drawable, private val middleDrawable: Drawable, private val rightDrawable: Drawable ) { private var previousDecorators = emptyList<DayViewDecorator>() fun clear(calendar: MaterialCalendarView) { previousDecorators.forEach { calendar.removeDecorator(it) } } fun applyForSelection(calendar: MaterialCalendarView, selectedDates: List<LocalDate>) { clear(calendar) val newDecorators = getDecoratorsForSelection(selectedDates) calendar.addDecorators(newDecorators) previousDecorators = newDecorators } private fun getDecoratorsForSelection(selectedDates: List<LocalDate>): List<DayViewDecorator> { val first = selectedDates.first() val last = selectedDates.last() val middle = selectedDates.subtract(listOf(first, last)) return listOf( RangeSelectionLeftDecorator(first, leftDrawable), RangeSelectionMiddleDecorator(middle, middleDrawable), RangeSelectionRightDecorator(last, rightDrawable) ) } }
@sampengilly how to use that, can you provide the details of RangeSelectionRightDecorator
?
Hey, it's been a while since I did that workaround and I no longer have access to the codebase where I did it. From memory the left, right, and middle decorators were simple decorator implementations along the lines of the dot examples, but with a drawable to suit. The drawable was also the fiddliest part as well I think, getting it to work right without any margin gaps. I can reach out to someone and see if I can get a copy of those classes and the drawables that I can share.
Thanks, @sampengilly I will try and will wait too, maybe I can check yours, even I work with java nowadays
@sampengilly i have hard time to figure out how to use RangeSelectionMiddleDecorator
, btw this is RangeSelectionRightDecorator
that i have figured out,
`
class RangeSelectionRightDecorator(last: org.threeten.bp.LocalDate, rightDrawable: Drawable) : DayViewDecorator {
var drawable = rightDrawable
var myDay = CalendarDay.from(last)
override fun shouldDecorate(day: CalendarDay): Boolean {
return day == myDay
}
override fun decorate(view: DayViewFacade) {
view.setSelectionDrawable(drawable)
}
}
`
i havent done testing on this class if there is a mistake please let me know
That's essentially all it is. I managed to find that code:
private class RangeSelectionLeftDecorator(
private val leftDate: LocalDate,
private val leftDrawable: Drawable
) : DayViewDecorator {
override fun shouldDecorate(day: CalendarDay): Boolean {
return leftDate == day.date
}
override fun decorate(view: DayViewFacade) {
view.setSelectionDrawable(leftDrawable)
view.addSpan(ForegroundColorSpan(Color.WHITE))
}
}
private class RangeSelectionMiddleDecorator(
private val middleDates: Set<LocalDate>,
private val middleDrawable: Drawable
) : DayViewDecorator {
override fun shouldDecorate(day: CalendarDay): Boolean {
return day.date in middleDates
}
override fun decorate(view: DayViewFacade) {
view.setSelectionDrawable(middleDrawable)
view.addSpan(ForegroundColorSpan(Color.BLACK))
}
}
private class RangeSelectionRightDecorator(
private val rightDate: LocalDate,
private val rightDrawable: Drawable
) : DayViewDecorator {
override fun shouldDecorate(day: CalendarDay): Boolean {
return rightDate == day.date
}
override fun decorate(view: DayViewFacade) {
view.setSelectionDrawable(rightDrawable)
view.addSpan(ForegroundColorSpan(Color.WHITE))
}
}
The color spans were to adjust text color from memory. It's been a while since I've looked at this.
Left Drawable:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:gravity="center_vertical|right" android:left="@dimen/cal_tile_height_half">
<shape android:shape="rectangle">
<solid android:color="@color/[surface color]"/>
</shape>
</item>
<item android:gravity="center">
<shape android:shape="oval">
<solid android:color="@color/[decorator color]"/>
<size android:height="@dimen/cal_tile_height" android:width="@dimen/cal_tile_height"/>
</shape>
</item>
</layer-list>
Middle drawable:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:gravity="center">
<shape android:shape="rectangle">
<solid android:color="@color/[surface color]"/>
</shape>
</item>
</layer-list>
Right drawable:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:gravity="center_vertical|left" android:right="@dimen/cal_tile_height_half">
<shape android:shape="rectangle">
<solid android:color="@color/[surface color]"/>
</shape>
</item>
<item android:gravity="center">
<shape android:shape="oval">
<solid android:color="@color/[decorator color]"/>
<size android:width="@dimen/cal_tile_height" android:height="@dimen/cal_tile_height"/>
</shape>
</item>
</layer-list>
@sampengilly how to use RangeSelectionDecorator
class ? im trying to put it on calendarView.addDecorator()
but i get
Type mismatch. Required: DayViewDecorator! Found: RangeSelectionDecorator
See the applyForSelection()
method in the earlier comment. Create the RangeSelectionDecorator
and keep a reference to it, then call that method whenever the selection changes on the calendar. It's a bit of a misnomer as it's really more of a helper class
I need a custom selector for range selection in which I could set different drawables if the date is the first selected, last selected, or in the middle. Since the decorator doesn't expose current date in
decorate
how can I achieve that. Cheers!