Open chrismabotuwana opened 5 years ago
@quentin41500 Really appreciate your input here
@chrismabotuwana Have you found a solution?
Okay, I fixed that. I created OtherDaysDecorator for other days and DayDecorator for month days:
public class DayDecorator implements DayViewDecorator {
private Context context;
private MaterialCalendarView calendarView;
public DayDecorator(Context context, MaterialCalendarView calendarView) {
this.context = context;
this.calendarView = calendarView;
}
@Override
public boolean shouldDecorate(CalendarDay day) {
Calendar cal1 = day.getCalendar();
Calendar cal2 = calendarView.getCurrentDate().getCalendar();
return cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) &&
cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH);
}
@Override
public void decorate(DayViewFacade view) {
view.addSpan(new TextAppearanceSpan(context, R.style.Day));
}
public class OtherDaysDecorator implements DayViewDecorator {
private Context context;
private MaterialCalendarView calendarView;
public OtherDaysDecorator(Context context, MaterialCalendarView calendarView) {
this.context = context;
this.calendarView = calendarView;
}
@Override
public boolean shouldDecorate(CalendarDay day) {
Calendar cal1 = day.getCalendar();
Calendar cal2 = calendarView.getCurrentDate().getCalendar();
return cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) &&
cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
cal1.get(Calendar.MONTH) != cal2.get(Calendar.MONTH);
}
@Override
public void decorate(DayViewFacade view) {
view.addSpan(new TextAppearanceSpan(context, R.style.OtherDay));
}
}
R.style.Day
it's a style with colors for month calendar days.
<style name="Day">
<item name="android:textColor">@color/calendar_day_text_color</item>
</style>
Other days:
<style name="OtherDay">
<item name="android:textColor">@color/calendar_otherday_text_color</item>
</style>
And my xml files using in these styles:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:color="@color/colorBackground"
android:state_checked="true"/>
<item
android:color="@color/colorOnSurface"
android:state_pressed="true"/>
<item
android:color="@color/greyMaterial"
android:state_enabled="false"/>
<item android:color="@color/colorOnSurface"/>
</selector>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:color="@color/colorBackground"
android:state_checked="true"/>
<item
android:color="@color/colorOnSurface"
android:state_pressed="true"/>
<item
android:color="@color/greyMaterial"
android:state_enabled="false"/>
<item android:color="@android:color/holo_orange_dark"/>
</selector>
In my Fragment
I create and add these decorators. Then, on every OnMonthClick
I repaint my decorators.
calendarView = view.findViewById(R.id.records_calendar);
DayDecorator dayDecorator = new DayDecorator(getContext(), calendarView);
calendarView.addDecorator(dayDecorator);
calendarView.setOnMonthChangedListener(new OnMonthChangedListener() {
@Override
public void onMonthChanged(MaterialCalendarView widget, CalendarDay date) {
Log.i(MainScreenActivity.TAG, "onMonthChanged: ");
calendarView.removeDecorator(todayDecorator);
calendarView.removeDecorator(daysDecorator);
calendarView.removeDecorator(otherDaysDecorator);
calendarView.invalidateDecorators();
calendarView.addDecorator(daysDecorator);
calendarView.addDecorator(otherDaysDecorator);
calendarView.addDecorator(todayDecorator);
}
});
otherDaysDecorator = new OtherDaysDecorator(getContext(), calendarView);
calendarView.addDecorator(otherDaysDecorator);
todayDecorator = new TodayDecorator(getContext());
calendarView.addDecorator(todayDecorator);
Calendar cal1 = day.getCalendar(); Calendar cal2 = calendarView.getCurrentDate().getCalendar();
These 2 lines give an error, unable to find the get calendar
@chrismabotuwana, @honeykapoor7
Approach #2.
I was unhappy with using decorators to resolve this simple thing that should be essential, so I went a little bit dipper.
In DayView.java
library has a problem, that actually leads to having Color.GRAY
as not only default, but to use it as the only color.
if (!isInMonth && shouldBeVisible) {
setTextColor(getTextColors().getColorForState(
new int[] { -android.R.attr.state_enabled }, Color.GRAY));
}
because of -
sign before android.R.attr.state_enabled
the color for attribute will never be found,
and all users will have only 'Color.GRAY' as color for dates out of month.
If you remove -
, there will be other problem - you will stuch with the color defined in android.R.attr.state_enabled
.
The solution would be to use custom view states:
1) Import library's code to your project by any way that you prefere.
2) In values/attrs.xml
declare custom attribute for DayView
:
<declare-styleable name="DayViewStates">
<attr name="state_out_of_month_enabled" format="boolean" />
</declare-styleable>
3) In selector file that you use for defining of your text style (app:mcv_dateTextAppearance="@style/yourCustomTextStyleSelector"
).
Apply your new view state attribute using xmlns:app="http://schemas.android.com/apk/res-auto"
namespace.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- Don't forget about selector's short-circuit rule-->
<item
app:state_out_of_month_enabled="true"
android:state_checked="false"
android:state_pressed="false"
android:color="@color/your_calendar_day_out_of_month_text_color" />
<item android:color="@color/anyColorForStateChecked" android:state_checked="true" />
<item android:color="@color/anyColorForStatePressed" android:state_pressed="true" />
<item android:color="@color/your_calendar_regular_day_text_color"/>
</selector>
4) In DayView.java
, you must override onCreateDrawableState
and add your new state.
private static final int[] STATE_OUT_OF_MONTH_ENABLED = {R.attr.state_out_of_month_enabled};
@Override
protected int[] onCreateDrawableState(int extraSpace) {
if (outOfMonthEnabled) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
mergeDrawableStates(drawableState, STATE_OUT_OF_MONTH_ENABLED);
return drawableState;
} else {
return super.onCreateDrawableState(extraSpace);
}
}
where outOfMonthEnabled
is a global property that is based on
outOfMonthEnabled = !isInMonth && shouldBeVisible;
which was previously a codition to trigger the default color hardcoding
setTextColor(getTextColors().getColorForState(new int[] { -android.R.attr.state_enabled }, Color.GRAY));
To trigger state change you need to call refreshDrawableState()
at the moment when your view goes to this state.
In our case, it will be the end of setEnabled()
method, right after outOfMonthEnabled
is evaluated.
In the end, it does require you to fork the library, but as soon as its not really updated recently - why not? This way should be less memory CPU and consuming, in opose to constant invalidation of decorators.
@quentin41500 what do you think, is this a good idea to make a PR with this contribution?
I have set a different color for date text using
and the related style
Therefore, all my date texts have the same color. I want my current month date texts to be white and other months' date texts to be grey. How can I achieve this?