Android上一个优雅、高度自定义、性能高效的日历控件,完美支持周视图,支持标记、自定义颜色、农历等,任意控制月视图显示、任意日期拦截条件、自定义周起始等。Canvas绘制,极速性能、占用内存低,支持简单定制即可实现任意自定义布局、自定义UI,支持收缩展开、性能非常高效, 这个控件内存和效率优势相当明显,而且真正做到收缩+展开,适配多种场景,支持同时多种颜色标记日历事务,支持多点触控,你真的想不到日历还可以如此优雅!
日历控件定制是移动开发平台上比较常见的而且比较难的需求,一般会遇到以下问题:
但现在有了全新的 CalendarView 控件,它解锁了各种姿势,而且你可以任意定制,直到你满足为止…
插拔式设计:好比插座一样,插上灯泡就会亮,插上风扇就会转,看用户需求什么而不是看插座有什么,只要是电器即可。此框架使用插拔式,既可以在编译时指定年月日视图,如:app:month_view=“xxx.xxx.MonthView.class”,也可在运行时动态更换年月日视图,如:CalendarView.setMonthViewClass(MonthView.Class),从而达到UI即插即用的效果,相当于框架不提供UI实现,让UI都由客户端实现,不至于日历UI都千篇一律,只需遵守插拔式接口即可随意定制,自由化程度非常高。
注意: 框架本身只是实现各自逻辑,不实现UI,UI如同一张白纸,任凭客户端自行通过Canvas绘制实现,如果不熟悉Canvas的,请自行了解各自Canvas.drawXXX方法,UI都靠Canvas实现,坐标都已经计算好了,因此怎么隐藏农历,怎么换某些日期的字,这些都不属于框架范畴,只要你想换,都能随便换。
AndroidStudio v3.5+
support版本使用
implementation 'com.haibin:calendarview:3.6.8
Androidx版本使用
implementation 'com.haibin:calendarview:3.7.1'
com.haibin
calendarview
3.7.0
pom
-keepclasseswithmembers class * {
public (android.content.Context);
}
或者针对性的使用混淆,请自行配置测试!
-keep class your project path.MonthView {
public (android.content.Context);
}
-keep class your project path.WeekBar {
public (android.content.Context);
}
-keep class your project path.WeekView {
public (android.content.Context);
}
-keep class your project path.YearView {
public (android.content.Context);
}
特别的,请注意不要复制这三个路径,自行替换您自己的自定义路径
app:month_view="com.haibin.calendarviewproject.simple.SimpleMonthView"
app:week_view="com.haibin.calendarviewproject.simple.SimpleWeekView"
app:week_bar_view="com.haibin.calendarviewproject.EnglishWeekBar"
特性如下
public void setRange(int minYear, int minYearMonth, int minYearDay,
int maxYear, int maxYearMonth, int maxYearDay) ;//置日期范围
public int getCurDay(); //今天
public int getCurMonth(); //当前的月份
public int getCurYear(); //今年
public boolean isYearSelectLayoutVisible();//年月份选择视图是否打开
public void closeYearSelectLayout();//关闭年月视图选择布局
public void showYearSelectLayout(final int year); //快速弹出年份选择月份
public void setOnMonthChangeListener(OnMonthChangeListener listener);//月份改变事件
public void setOnYearChangeListener(OnYearChangeListener listener);//年份切换事件
public void setOnCalendarSelectListener(OnCalendarSelectListener listener)//日期选择事件
public void setOnCalendarLongClickListener(OnCalendarLongClickListener listener);//日期长按事件
public void setOnCalendarLongClickListener(OnCalendarLongClickListener listener, boolean preventLongPressedSelect);//日期长按事件
public void setOnCalendarInterceptListener(OnCalendarInterceptListener listener);//日期拦截和日期有效性绘制
public void setSchemeDate(Map mSchemeDates);//标记日期
public void update();//动态更新
public Calendar getSelectedCalendar(); //获取选择的日期
/**
* 特别的,如果你需要自定义或者使用其它选择器,可以用以下方法进行和日历联动
*/
public void scrollToCurrent();//滚动到当前日期
public void scrollToCurrent(boolean smoothScroll);//滚动到当前日期
public void scrollToYear(int year);//滚动到某一年
public void scrollToPre();//滚动到上一个月
public void scrollToNext();//滚动到下一个月
public void scrollToCalendar(int year, int month, int day);//滚动到指定日期
public Calendar getMinRangeCalendar();//获得最小范围日期
public Calendar getMaxRangeCalendar();//获得最大范围日期
/**
* 设置背景色
*
* @param monthLayoutBackground 月份卡片的背景色
* @param weekBackground 星期栏背景色
* @param lineBg 线的颜色
*/
public void setBackground(int monthLayoutBackground, int weekBackground, int lineBg)
/**
* 设置文本颜色
*
* @param curMonthTextColor 当前月份字体颜色
* @param otherMonthColor 其它月份字体颜色
* @param lunarTextColor 农历字体颜色
*/
public void setTextColor(int curMonthTextColor,int otherMonthColor,int lunarTextColor)
/**
* 设置选择的效果
*
* @param style 选中的style CalendarCardView.STYLE_FILL or CalendarCardView.STYLE_STROKE
* @param selectedThemeColor 选中的标记颜色
* @param selectedTextColor 选中的字体颜色
*/
public void setSelectedColor(int style, int selectedThemeColor, int selectedTextColor)
/**
* 设置标记的色
*
* @param style 标记的style CalendarCardView.STYLE_FILL or CalendarCardView.STYLE_STROKE
* @param schemeColor 标记背景色
* @param schemeTextColor 标记字体颜色
*/
public void setSchemeColor(int style, int schemeColor, int schemeTextColor)
/**
* 设置星期栏的背景和字体颜色
*
* @param weekBackground 背景色
* @param weekTextColor 字体颜色
*/
public void setWeeColor(int weekBackground, int weekTextColor)
public void expand(); //展开
public void shrink(); //收缩
public boolean isExpand();//是否展开了
boolean isWeekend();//判断是不是周末,可以用不同的画笔绘制周末的样式
int getWeek();//获取星期
String getSolarTerm();//获取24节气,可以用不同颜色标记不同节日
String getGregorianFestival();//获取公历节日,自由判断,把节日换上喜欢的颜色
String getTraditionFestival();//获取传统节日
boolean isLeapYear();//是否是闰年
int getLeapMonth();//获取闰月
boolean isSameMonth(Calendar calendar);//是否相同月
int compareTo(Calendar calendar);//比较日期大小 -1 0 1
long getTimeInMillis();//获取时间戳
int differ(Calendar calendar);//日期运算,相差多少天
继承自己的月视图和周视图,只需要依次实现
绘制选中:onDrawSelected、
绘制事务:onDrawScheme、
绘制文本:onDrawText 这三个回调即可,参数和坐标都已经在回调函数上实现好,周视图也是一样的逻辑,只是不需要y参数
/**
* 定制高仿魅族日历界面,按你的想象力绘制出各种各样的界面
*
*/
public class MeiZuMonthView extends MonthView {
/**
* 绘制选中的日子
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme hasScheme 非标记的日期
* @return 返回true 则绘制onDrawScheme,因为这里背景色不是是互斥的,所以返回true
*/
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
//这里绘制选中的日子样式,看需求需不需要继续调用onDrawScheme
return true;
}
/**
* 绘制标记的事件日子
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
*/
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
//这里绘制标记的日期样式,想怎么操作就怎么操作
}
/**
* 绘制文本
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme 是否是标记的日期
* @param isSelected 是否选中
*/
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
//这里绘制文本,不要再问我怎么隐藏农历了,不要再问我怎么把某个日期换成特殊字符串了,要怎么显示你就在这里怎么画,你不画就不显示,是看你想怎么显示日历的,而不是看框架
}
}
app:month_view="com.haibin.calendarviewproject.MeiZuMonthView"
app:week_view="com.haibin.calendarviewproject.MeiZuWeekView"
如果继承这2个,MonthView、WeekView,即select_mode="default_mode",这是默认的手机自带的日历模式,会自动选择月的第一天,不支持拦截器,
也可以设置select_mode="single_mode",即单选模式,支持拦截器
如果继承这2个,RangeMonthView、RangeWeekView,即select_mode="range_mode",这是范围选择模式,支持拦截器
如果继承这2个,MultiMonthView、MultiWeekView,即select_mode="multi_mode",这是多选模式,支持拦截器
如果静态模式无法满足你的需求,你可能需要动态变换定制的视图界面,你可以使用热插拔特性
mCalendarView.setWeekView(MeiZuWeekView.class);
mCalendarView.setMonthView(MeiZuMonthView.class);
如果你需要可收缩的日历,你可以在 CalendarView 父布局添加 CalendarLayout,当然你不需要周视图也可以不用,例如原生日历,使用如下:
public void setOnViewChangeListener(OnViewChangeListener listener);
CalendarLayout 有很多特性可提供周月视图无缝切换,而且,平滑手势不抖动!使用 CalendarLayout,你需要指定 calendar_content_view_id,用他来平移收缩月视图
CalendarView.scrollToCalendar();
CalendarView.scrollToNext();
CalendarView.scrollToPre();
CalendarView.scrollToXXX();
app:week_start_with="mon、sun、sat"
CalendarView.setWeekStarWithSun();
CalendarView.setWeekStarWithMon();
CalendarView.setWeekStarWithSat();
public class CustomRangeMonthView extends RangeMonthView{
}
public class CustomRangeWeekView extends RangeWeekView{
}
CalendarView.setRange(int minYear, int minYearMonth, int minYearDay,
int maxYear, int maxYearMonth, int maxYearDay)
//设置日期拦截事件
mCalendarView.setOnCalendarInterceptListener(new CalendarView.OnCalendarInterceptListener() {
@Override
public boolean onCalendarIntercept(Calendar calendar) {
//这里写拦截条件,返回true代表拦截,尽量以最高效的代码执行
return calendar.isWeekend();
}
@Override
public void onCalendarInterceptClick(Calendar calendar, boolean isClick) {
//todo 点击拦截的日期回调
}
});
boolean isInRange = isInRange(calendar);//日期是否在范围内,超出范围的可以置灰
boolean isEnable = !onCalendarIntercept(calendar);//日期是否可用,没有被拦截,被拦截的可以置灰
githup
gitee