1818import com .google .android .material .R ;
1919
2020import android .content .Context ;
21+ import android .content .res .ColorStateList ;
2122import android .content .res .TypedArray ;
23+ import android .graphics .Canvas ;
24+ import android .graphics .Paint ;
2225import android .os .Parcel ;
2326import android .os .Parcelable ;
27+ import androidx .annotation .ColorInt ;
2428import androidx .annotation .Nullable ;
2529import androidx .annotation .RestrictTo ;
2630import androidx .annotation .RestrictTo .Scope ;
31+ import androidx .annotation .StyleRes ;
2732import com .google .android .material .resources .MaterialAttributes ;
33+ import com .google .android .material .resources .MaterialResources ;
2834import androidx .core .util .Pair ;
2935import android .text .format .DateUtils ;
36+ import android .view .View ;
3037import android .widget .TextView ;
3138import java .util .Calendar ;
3239
@@ -41,6 +48,38 @@ public class DateRangeGridSelector implements GridSelector<Pair<Calendar, Calend
4148
4249 private Calendar selectedStartItem = null ;
4350 private Calendar selectedEndItem = null ;
51+ private boolean stylesInitialized = false ;
52+ private Paint rangeFillPaint ;
53+ @ ColorInt private int rangeFillColor ;
54+ @ StyleRes private int dayStyle ;
55+ @ StyleRes private int selectedStyle ;
56+ @ StyleRes private int todayStyle ;
57+
58+ // The context is not available on construction, so we lazily initialize styles.
59+ private void initializeStyles (Context context ) {
60+ if (stylesInitialized ) {
61+ return ;
62+ }
63+ stylesInitialized = true ;
64+
65+ int rangeCalendarStyle =
66+ MaterialAttributes .resolveOrThrow (
67+ context ,
68+ R .attr .materialDateRangePickerStyle ,
69+ MaterialCalendar .class .getCanonicalName ());
70+
71+ TypedArray calendarAttributes =
72+ context .obtainStyledAttributes (rangeCalendarStyle , R .styleable .MaterialCalendar );
73+ ColorStateList rangeFillColorList =
74+ MaterialResources .getColorStateList (
75+ context , calendarAttributes , R .styleable .MaterialCalendar_rangeFillColor );
76+ dayStyle = calendarAttributes .getResourceId (R .styleable .MaterialCalendar_dayStyle , 0 );
77+ selectedStyle =
78+ calendarAttributes .getResourceId (R .styleable .MaterialCalendar_daySelectedStyle , 0 );
79+ todayStyle = calendarAttributes .getResourceId (R .styleable .MaterialCalendar_dayTodayStyle , 0 );
80+ rangeFillColor = rangeFillColorList .getDefaultColor ();
81+ calendarAttributes .recycle ();
82+ }
4483
4584 @ Override
4685 public void select (Calendar selection ) {
@@ -57,50 +96,114 @@ public void select(Calendar selection) {
5796 @ Override
5897 public void drawCell (TextView cell , Calendar item ) {
5998 Context context = cell .getContext ();
60- int rangeCalendarStyle =
61- MaterialAttributes .resolveOrThrow (
62- context ,
63- R .attr .materialDateRangePickerStyle ,
64- MaterialCalendar .class .getCanonicalName ());
65-
99+ initializeStyles (context );
66100 int style ;
67- TypedArray stylesList =
68- context .obtainStyledAttributes (rangeCalendarStyle , R .styleable .MaterialCalendar );
69101 if (item .equals (selectedStartItem ) || item .equals (selectedEndItem )) {
70- style = stylesList . getResourceId ( R . styleable . MaterialCalendar_daySelectedStyle , 0 ) ;
102+ style = selectedStyle ;
71103 } else if (DateUtils .isToday (item .getTimeInMillis ())) {
72- style = stylesList . getResourceId ( R . styleable . MaterialCalendar_dayTodayStyle , 0 ) ;
104+ style = todayStyle ;
73105 } else {
74- style = stylesList . getResourceId ( R . styleable . MaterialCalendar_dayStyle , 0 ) ;
106+ style = dayStyle ;
75107 }
76- stylesList .recycle ();
77-
78108 CalendarGridSelectors .colorCell (cell , style );
79109 }
80110
111+ @ Override
112+ public void onCalendarMonthDraw (Canvas canvas , MaterialCalendarGridView gridView ) {
113+ initializeStyles (gridView .getContext ());
114+ if (rangeFillPaint == null ) {
115+ rangeFillPaint = new Paint ();
116+ rangeFillPaint .setColor (rangeFillColor );
117+ }
118+ MonthAdapter monthAdapter = gridView .getAdapter ();
119+ Calendar firstOfMonth = monthAdapter .getItem (monthAdapter .firstPositionInMonth ());
120+ Calendar lastOfMonth = monthAdapter .getItem (monthAdapter .lastPositionInMonth ());
121+ if (skipMonth (firstOfMonth , lastOfMonth , selectedStartItem , selectedEndItem )) {
122+ return ;
123+ }
124+
125+ int firstHighlightPosition ;
126+ int rangeHighlightStart ;
127+ if (selectedStartItem .before (firstOfMonth )) {
128+ firstHighlightPosition = monthAdapter .firstPositionInMonth ();
129+ rangeHighlightStart =
130+ firstHighlightPosition == 0
131+ ? 0
132+ : gridView .getChildAt (firstHighlightPosition - 1 ).getRight ();
133+ } else {
134+ firstHighlightPosition =
135+ monthAdapter .dayToPosition (selectedStartItem .get (Calendar .DAY_OF_MONTH ));
136+ rangeHighlightStart = horizontalMidPoint (gridView .getChildAt (firstHighlightPosition ));
137+ }
138+
139+ int lastHighlightPosition ;
140+ int rangeHighlightEnd ;
141+ if (selectedEndItem .after (lastOfMonth )) {
142+ lastHighlightPosition = monthAdapter .lastPositionInMonth ();
143+ rangeHighlightEnd =
144+ lastHighlightPosition == gridView .getCount () - 1
145+ ? gridView .getWidth ()
146+ : gridView .getChildAt (lastHighlightPosition + 1 ).getLeft ();
147+ } else {
148+ lastHighlightPosition =
149+ monthAdapter .dayToPosition (selectedEndItem .get (Calendar .DAY_OF_MONTH ));
150+ rangeHighlightEnd = horizontalMidPoint (gridView .getChildAt (lastHighlightPosition ));
151+ }
152+
153+ int firstRow = (int ) monthAdapter .getItemId (firstHighlightPosition );
154+ int lastRow = (int ) monthAdapter .getItemId (lastHighlightPosition );
155+ for (int row = firstRow ; row <= lastRow ; row ++) {
156+ int firstPositionInRow = row * gridView .getNumColumns ();
157+ int lastPositionInRow = firstPositionInRow + gridView .getNumColumns () - 1 ;
158+ View firstView = gridView .getChildAt (firstPositionInRow );
159+ int top = firstView .getTop ();
160+ int bottom = firstView .getBottom ();
161+ int left = firstPositionInRow > firstHighlightPosition ? 0 : rangeHighlightStart ;
162+ int right =
163+ lastHighlightPosition > lastPositionInRow ? gridView .getWidth () : rangeHighlightEnd ;
164+ canvas .drawRect (left , top , right , bottom , rangeFillPaint );
165+ }
166+ }
167+
81168 @ Override
82169 @ Nullable
83170 public Pair <Calendar , Calendar > getSelection () {
84- Calendar start = getStart ();
85- Calendar end = getEnd ();
86- if (start == null || end == null ) {
171+ if (selectedStartItem == null || selectedEndItem == null ) {
87172 return null ;
88173 }
89- return new Pair <>(getStart (), getEnd () );
174+ return new Pair <>(selectedStartItem , selectedEndItem );
90175 }
91176
92- /** Returns a {@link java.util.Calendar} representing the start of the range */
177+ /** Returns a {@link java.util.Calendar} representing the start of the range. */
93178 @ Nullable
94179 public Calendar getStart () {
180+ if (selectedStartItem == null || selectedEndItem == null ) {
181+ return null ;
182+ }
95183 return selectedStartItem ;
96184 }
97185
98- /** Returns a {@link java.util.Calendar} representing the end of the range */
186+ /** Returns a {@link java.util.Calendar} representing the end of the range. */
99187 @ Nullable
100188 public Calendar getEnd () {
189+ if (selectedStartItem == null || selectedEndItem == null ) {
190+ return null ;
191+ }
101192 return selectedEndItem ;
102193 }
103194
195+ private boolean skipMonth (
196+ Calendar firstOfMonth , Calendar lastOfMonth , Calendar startDay , Calendar endDay ) {
197+ if (startDay == null || endDay == null ) {
198+ return true ;
199+ }
200+ return startDay .after (lastOfMonth ) || endDay .before (firstOfMonth );
201+ }
202+
203+ private int horizontalMidPoint (View view ) {
204+ return view .getLeft () + view .getWidth () / 2 ;
205+ }
206+
104207 /* Parcelable interface */
105208
106209 /** {@link Parcelable.Creator} */
@@ -111,6 +214,11 @@ public DateRangeGridSelector createFromParcel(Parcel source) {
111214 DateRangeGridSelector dateRangeGridSelector = new DateRangeGridSelector ();
112215 dateRangeGridSelector .selectedStartItem = (Calendar ) source .readSerializable ();
113216 dateRangeGridSelector .selectedEndItem = (Calendar ) source .readSerializable ();
217+ dateRangeGridSelector .stylesInitialized = (Boolean ) source .readValue (null );
218+ dateRangeGridSelector .rangeFillColor = source .readInt ();
219+ dateRangeGridSelector .dayStyle = source .readInt ();
220+ dateRangeGridSelector .selectedStyle = source .readInt ();
221+ dateRangeGridSelector .todayStyle = source .readInt ();
114222 return dateRangeGridSelector ;
115223 }
116224
@@ -129,5 +237,10 @@ public int describeContents() {
129237 public void writeToParcel (Parcel dest , int flags ) {
130238 dest .writeSerializable (selectedStartItem );
131239 dest .writeSerializable (selectedEndItem );
240+ dest .writeValue (stylesInitialized );
241+ dest .writeInt (rangeFillColor );
242+ dest .writeInt (dayStyle );
243+ dest .writeInt (selectedStyle );
244+ dest .writeInt (todayStyle );
132245 }
133246}
0 commit comments