博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android精美日历控件CalendarView自定义使用完全解析
阅读量:7112 次
发布时间:2019-06-28

本文共 12194 字,大约阅读时间需要 40 分钟。

项目github地址

此框架采用组合的方式,各个模块互相独立,可自由采用各种提供的控件组合,完全自定义自己需要的UI,周视图和月视图可通过简单自定义任意自由绘制,不怕美工提需求!!!下面教程将介绍如何实现3个API,自定义Canvas绘制日历

CalendarView的优势:

1、热插拔设计,根据不同的UI需求完全自定义UI,简单几步即可实现,自定义事件日历标记、颜色、农历等

2、完全Canvas绘制,性能和速度都很不错,相比大多数基于GridView或RecyclerView实现的占用内存更低,启动速度更快

3、支持收缩、展开、快速年月份选择等

4、简洁易懂的源码,易学习。

Gradle

compile 'com.haibin:calendarview:3.2.9'复制代码
com.haibin
calendarview
3.2.9
pom
复制代码

混淆proguard-rules

-keepclasseswithmembers class * {    public 
(android.content.Context);}复制代码

国际惯例,先上一个自定义效果图,结尾还有几个其它效果图,可自己自定义

     

各个类功能介绍

CalendarLayout

这是个辅助类,负责CalendarView的收缩控制功能,如果不需要收缩功能,无需使用它,一般使用教程如下

复制代码

CalendarLayout api

public void expand(); //展开public void shrink(); //收缩public boolean isExpand();//是否已经展开复制代码
复制代码
CalendarView

真正的日历类,可以自行通过attr配置

复制代码

完整attr

 
复制代码

CalendarView api

public int getCurDay(); //今天public int getCurMonth(); //当前的月份public int getCurYear(); //今年public void showSelectLayout(final int year); //快速弹出年份选择月份public void closeSelectLayout(final int position); //关闭选择年份并跳转日期/*** 设置日期范围** @param minYear      最小年份* @param minYearMonth 最小年份对应月份* @param maxYear      最大月份* @param maxYearMonth 最大月份对应月份*/public void setRange(int minYear, int minYearMonth,                         int maxYear, int maxYearMonth) public void setOnYearChangeListener(OnYearChangeListener listener);//年份切换事件public void setOnDateSelectedListener(OnDateSelectedListener listener);//日期选择事件public void setSchemeDate(List
mSchemeDate);//标记日期public void update();//动态更新public Calendar getSelectedCalendar(); //获取选择的日期public void scrollToPre();//滚动到上一个月public void scrollToNext();//滚动到下一个月public void scrollToCalendar(int year, int month, int day);//滚动到指定日期/** * 设置背景色 * * @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 yearViewBackground 年份卡片的背景色 * @param weekBackground 星期栏背景色 * @param lineBg 线的颜色*/public void setBackground(int yearViewBackground, int weekBackground, int lineBg)复制代码

这个控件的特别之处就是它的UI是可以交给客户端自由绘制的,因此可以自由发挥想象力,绘制你需要的日历效果UI

接下来介绍如何完全自定义日历,自定义日历需要同时自定义月视图和周视图,代码几乎一样,需要实现三个回调函数即可,如下:

onDrawSelectedonDrawSchemeonDrawText复制代码
/** * 首先继承月视图,假如我们想实现高仿魅族的日历 */public class MeiZuMonthView extends MonthView {    /**     * 自定义魅族标记的文本画笔     */    private Paint mTextPaint = new Paint();    /**     * 自定义魅族标记的圆形背景     */    private Paint mSchemeBasicPaint = new Paint();    private float mRadio;    private int mPadding;    private float mSchemeBaseLine;    public MeiZuMonthView(Context context) {        super(context);        mTextPaint.setTextSize(dipToPx(context, 8));        mTextPaint.setColor(0xffffffff);        mTextPaint.setAntiAlias(true);        mTextPaint.setFakeBoldText(true);        mSchemeBasicPaint.setAntiAlias(true);        mSchemeBasicPaint.setStyle(Paint.Style.FILL);        mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);        mSchemeBasicPaint.setFakeBoldText(true);        mRadio = dipToPx(getContext(), 7);        mPadding = dipToPx(getContext(), 4);        Paint.FontMetrics metrics = mSchemeBasicPaint.getFontMetrics();        mSchemeBaseLine = mRadio - metrics.descent + (metrics.bottom - metrics.top) / 2 + dipToPx(getContext(), 1);    }    /**     * 绘制选中的日子     * @param canvas    canvas     * @param calendar  日历日历calendar     * @param x         日历Card x起点坐标     * @param y         日历Card y起点坐标     * @param hasScheme hasScheme 非标记的日期     * @return 返回true 则会继续绘制onDrawScheme,因为这里背景色不是是互斥的,所以返回true,返回false,则点击scheme标记的日子,则不继续绘制onDrawScheme,自行选择即可     */    @Override    protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {        mSelectedPaint.setStyle(Paint.Style.FILL);        mSelectedPaint.setColor(0x80cfcfcf);        canvas.drawRect(x + mPadding, y + mPadding, x + mItemWidth - mPadding, y + mItemHeight - mPadding, mSelectedPaint);        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) {        mSchemeBasicPaint.setColor(calendar.getSchemeColor());        canvas.drawCircle(x + mItemWidth - mPadding - mRadio / 2, y + mPadding + mRadio, mRadio, mSchemeBasicPaint);        canvas.drawText(calendar.getScheme(), x + mItemWidth - mPadding - mRadio, y + mPadding + mSchemeBaseLine, mTextPaint);    }    /**     * 绘制文本     * @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) {        int cx = x + mItemWidth / 2;        int top = y - mItemHeight / 6;        if (isSelected) {
//优先绘制选择的 canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top, mSelectTextPaint); canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mSelectedLunarTextPaint); } else if (hasScheme) {
//否则绘制具有标记的 canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top, calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint); canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mCurMonthLunarTextPaint); } else {
//最好绘制普通文本 canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top, calendar.isCurrentDay() ? mCurDayTextPaint : calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint); canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, calendar.isCurrentDay() ? mCurDayLunarTextPaint : calendar.isCurrentMonth() ? mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint); } } /** * dp转px * * @param context context * @param dpValue dp * @return px */ private static int dipToPx(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); }}复制代码

实现自定义周视图,周视图除了三个回调函数少了一个y参数,其它一样,因为周视图只有一行,所以可直接copy MonthView的代码,令y=0即可,如下

public class MeizuWeekView extends WeekView {    private Paint mTextPaint = new Paint();    private Paint mSchemeBasicPaint = new Paint();    private float mRadio;    private int mPadding;    private float mSchemeBaseLine;    public MeizuWeekView(Context context) {        super(context);        mTextPaint.setTextSize(dipToPx(context, 8));        mTextPaint.setColor(0xffffffff);        mTextPaint.setAntiAlias(true);        mTextPaint.setFakeBoldText(true);        mSchemeBasicPaint.setAntiAlias(true);        mSchemeBasicPaint.setStyle(Paint.Style.FILL);        mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);        mSchemeBasicPaint.setColor(0xffed5353);        mSchemeBasicPaint.setFakeBoldText(true);        mRadio = dipToPx(getContext(), 7);        mPadding = dipToPx(getContext(), 4);        Paint.FontMetrics metrics = mSchemeBasicPaint.getFontMetrics();        mSchemeBaseLine = mRadio - metrics.descent + (metrics.bottom - metrics.top) / 2 + dipToPx(getContext(), 1);    }    /**     *     * @param canvas    canvas     * @param calendar  日历日历calendar     * @param x         日历Card x起点坐标     * @param hasScheme hasScheme 非标记的日期     * @return true 则绘制onDrawScheme,因为这里背景色不是是互斥的     */    @Override    protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme) {        mSelectedPaint.setStyle(Paint.Style.FILL);        mSelectedPaint.setColor(0x80cfcfcf);        canvas.drawRect(x + mPadding, mPadding, x + mItemWidth - mPadding, mItemHeight - mPadding, mSelectedPaint);        return true;    }    @Override    protected void onDrawScheme(Canvas canvas, Calendar calendar, int x) {        mSchemeBasicPaint.setColor(calendar.getSchemeColor());        canvas.drawCircle(x + mItemWidth - mPadding - mRadio / 2, mPadding + mRadio, mRadio, mSchemeBasicPaint);        canvas.drawText(calendar.getScheme(), x + mItemWidth - mPadding - mRadio, mPadding + mSchemeBaseLine, mTextPaint);    }    @Override    protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) {        int cx = x + mItemWidth / 2;        int top = -mItemHeight / 6;        if (isSelected) {            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,                    mSelectTextPaint);            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, mSelectedLunarTextPaint);        } else if (hasScheme) {            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,                    calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, mCurMonthLunarTextPaint);        } else {            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,                    calendar.isCurrentDay() ? mCurDayTextPaint :                            calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,                    calendar.isCurrentDay() ? mCurDayLunarTextPaint :                            calendar.isCurrentMonth() ? mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);        }    }    /**     * dp转px     *     * @param context context     * @param dpValue dp     * @return px     */    private static int dipToPx(Context context, float dpValue) {        final float scale = context.getResources().getDisplayMetrics().density;        return (int) (dpValue * scale + 0.5f);    }}复制代码

最后通过CalendarView两个attr配置class路径即可,是不是很像自定义Behavior?

app:month_view="com.haibin.calendarviewproject.meizu.MeiZuMonthView"app:week_view="com.haibin.calendarviewproject.meizu.MeizuWeekView"复制代码

最后各种自定义UI效果自由欣赏,源码都在demo

     

     

     

     

建议clone APP Demo,里面作者实现了几种类型的风格,可以参考实现

项目开源地址,一点贡献

转载地址:http://gjmhl.baihongyu.com/

你可能感兴趣的文章
listView 添加addHeaderView和addFooterView以及handler.postDelayed的使用
查看>>
MySQL数据类型及列类型
查看>>
PHP 查找链表倒数第i个节点
查看>>
一个简单的基于编辑距离的英文单词查错(Python) - Muilpin.Miao的日志 - 网易博客...
查看>>
JavaScript试题【解析+答案】
查看>>
链接相关 & 预处理
查看>>
Oracle Applications 相关文档
查看>>
1300万像素高清双核旗舰 索尼LT30p评测_手机_科技时代_新浪网
查看>>
《BOOST程序库完全开发指南》 第06章 正确性与测试
查看>>
LinkedHashMap
查看>>
A lunch in Gordon Market with WWF
查看>>
深蓝词库转换1.9发布——支持英库拼音、搜狗bin格式、FIT、中州韵等
查看>>
Listview首列固定,不能移动到其他列
查看>>
升级TFS2012查看SOURCE-history部分提示TF14045: The identity xxx is not a recognized identity
查看>>
python 可以写 桌面应用程序不?需要依赖 python 么?python 是不是 类似.net framework?...
查看>>
【Web技术学习】PHP学习笔记
查看>>
(转)理解SQLSERVER中的排序规则
查看>>
sizeof和strlen与带汉字字符的
查看>>
TCP 套接字函数
查看>>
安卓Android手机系统内文件夹目录解释
查看>>