满足你各种姿势的最美Android开源日历

栏目: Android · 发布时间: 7年前

内容简介:但现在有了全新的CalendarView控件,它解锁了各种姿势,而且你可以不断调教它,直到你满足为止...
  • 性能差,加载速度慢 ,原因是各种基于GridView或RecyclerView等ViewGroup实现的日历,控件数太多,假设一个月视图界面有42个item,每个item里面分别就有2个子TextView:天数、农历数和本身3个控件,这样一个月视图就有42 * 3+1(RecyclerView or GridView),清楚ViewPager特性的开发者就会明白,一般ViewPager持有3个item,那么一个日历控件持有的View控件数的数量将达到 1(ViewPager)+ 3(RecyclerView or GridView) + 3 * 42 * 3 = 382 ,如果用1个View来代替RecyclerView等,用Canvas来代替各种TextView,那View的数量瞬间将下降360+,内存和性能优势将相当明显了
  • 难定制 一般日历框架发布的同时也将UI风格确定下来了,假如人人都使用这个日历框架,那么将会千篇一律,难以突出自己的风格,要么就得改源码,成本太大,不太实际
  • 功能性不足 例如无法自定义周起始、无法更改选择模式、动态设置UI等等
  • 无法满足产品经理提出的变态需求 今天产品经历说我们要这样的实现、明天跟你说这里得改、后天说我们得限制一些日期...

但现在有了全新的CalendarView控件,它解锁了各种姿势,而且你可以不断调教它,直到你满足为止...

国际惯例:先放项目github地址

https://github.com/huanghaibin-dev/CalendarView

国内惯例:无图言吊

满足你各种姿势的最美Android开源日历 满足你各种姿势的最美Android开源日历

满足你各种姿势的最美Android开源日历 满足你各种姿势的最美Android开源日历

CalendarView的骚特性

  • 基于Canvas绘制,极速性能
  • 热插拔思想,任意定制周视图、月视图,即插即用!
  • 支持单选、多选、国内手机日历默认自动选择等选择模式
  • 支持静态、动态设置周起始,一行代码搞定
  • 支持静态、动态设置日历项高度、日历填充模式
  • 支持设置任意日期范围、任意拦截日期
  • 支持多点触控、手指平滑切换过渡,拒绝界面抖动
  • 既然这么多支持,那一定支持英语、繁体、简体,任意定制实现

接下来请看CalendarView骚操作,看看它是可以怎样调教的

  • 你这样继承自己的月视图和周视图,只需要依次实现绘制选中:onDrawSelected、绘制事务:onDrawScheme、绘制文本:onDrawText这三个回调即可,参数和坐标都已经在回调函数上实现好,周视图也是一样的逻辑,只是不需要y参数
/**
 * 定制高仿魅族日历界面,按你的想象力绘制出各种各样的界面
 * Created by huanghaibin on 2017/11/15.
 */

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) {
        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) {
        canvas.drawCircle(x + mItemWidth - mPadding - mRadio / 2, y + mPadding + mRadio, mRadio, mSchemeBasicPaint);
        canvas.drawText(calendar.getScheme(),
                x + mItemWidth - mPadding - mRadio / 2 - getTextWidth(calendar.getScheme()) / 2,
                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;

        boolean isInRange = isInRange(calendar);

        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() && isInRange ? 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() && isInRange ? mCurMonthTextPaint : mOtherMonthTextPaint);
            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,
                    calendar.isCurrentDay() && isInRange ? mCurDayLunarTextPaint :
                            calendar.isCurrentMonth() ? mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);
        }
    }
}
复制代码
  • 当你实现好之后,直接在xml界面上添加特性,可以即时预览效果:
<attr name="month_view" format="string" /><!--自定义月视图路径-->
<attr name="week_view" format="string" /> <!--自定义周视图路径-->

app:month_view="com.haibin.calendarviewproject.MeiZuCalendarCardView"
app:week_view="com.haibin.calendarviewproject.MeiZuWeekView"

复制代码
  • 但这种静态模式可能无法满足你的需求,你可能需要动态变换定制的视图界面,于是你可以使用热插拔特性,即插即用,不爽就换:
mCalendarView.setWeekView(MeizuWeekView.class);

mCalendarView.setMonthView(MeizuMonthView.class);
 
复制代码
  • CalendarView也提供了高效便利的年视图,可以快速切换年份、月份,十分便利
满足你各种姿势的最美Android开源日历
  • 但年视图也不一定就适合产品经理的胃口,产品经理希望像小米日历一样,弹出DatePickerView,通过它来跳转日期,于是你可以使用以下的API来让日历与其它控件联动
CalendarView.scrollToCalendar();

CalendarView.scrollToNext();

CalendarView.scrollToPre();

CalendarView.scrollToXXX();

复制代码
  • 你也许需要像魅族日历一样,可以静态、动态更换周起始
app:week_start_with="mon、sun、sat"

CalendarView.setWeekStarWithSun();

CalendarView.setWeekStarWithMon();

CalendarView.setWeekStarWithSat();

复制代码
  • 假如你是做酒店、旅游等应用场景的APP的,那么需要可选范围的日历,你可以这样继承,和普通视图实现完全一样
public class CustomRangeMonthView extends RangeMonthView{
    
}

public class CustomRangeWeekView extends RangeWeekView{
    
}

复制代码
  • 然后你需要设置选择模式为范围模式:select_mode="range_mode"

  • 酒店式日历场景当然是不能从昨天开始订房的,也不能无限期订房,所以你需要静态或动态设置日历范围、精确到具体某一天!!!

<attr name="min_year" format="integer" />
<attr name="max_year" format="integer" />
<attr name="min_year_month" format="integer" />
<attr name="max_year_month" format="integer" />
<attr name="min_year_day" format="integer" />
<attr name="max_year_day" format="integer" />

CalendarView.setRange(int minYear, int minYearMonth, int minYearDay,
         int maxYear, int maxYearMonth, int maxYearDay)

复制代码
  • 当然还有更特殊的日子也是不能选择的,例如:某月某号起这N天时间内因为超强台风来袭,酒店需停止营业N天,这段期间不可订房,这时日期拦截器就排上用场了
//设置日期拦截事件
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);//日期是否可用,没有被拦截,被拦截的可以置灰

复制代码
  • 假如你是做清单类、任务类APP的,可能会有这样的需求:标记某天事务的进度,这也很简单,因为:日历界面长什么样,你自己说了算!!!
满足你各种姿势的最美Android开源日历
  • 也许你只需要像原生日历那样就够了,但原生日历那奇怪且十分不友好的style,受到theme的影响,各种头疼,使用此控件,你只需要简简单单定制月视图就够了, CalendarView 能非常简单就高仿各种日历UI

  • CalendarView提供了 setSchemeDate(Map<String, Calendar> mSchemeDates) 这个十分高效的API用来动态标记事务,即时你的数据量达到数千、数万、数十万,都不会对UI渲染造成影响

  • 日历类 Calendar 提供了许多十分有用的API

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);//日期运算,相差多少天
复制代码

其它各种场景姿势就不多说了,你得自己去解锁,一起看Demo以及各种APP的风骚实现

满足你各种姿势的最美Android开源日历 满足你各种姿势的最美Android开源日历

满足你各种姿势的最美Android开源日历 满足你各种姿势的最美Android开源日历

满足你各种姿势的最美Android开源日历 满足你各种姿势的最美Android开源日历

写在最后,框架本身是为了解决各种各样的场景而设计的,UI本身是靠自己绘制的,非常简单,不懂的请优先看Demo,你可以自由发挥想象力定制最喜欢的日历,只有你想不到,Demo基本给出了各种场景的实现思路。觉得可以的请给个star或者留下你宝贵的意见。


以上所述就是小编给大家介绍的《满足你各种姿势的最美Android开源日历》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

构建之法(第三版)

构建之法(第三版)

邹欣 / 人民邮电出版社 / 2017-6 / 69.00元

软件工程牵涉的范围很广, 同时也是一般院校的同学反映比较空洞乏味的课程。 但是,软件工程 的技术对于投身 IT 产业的学生来说是非常重要的。作者有在世界一流软件企业 20 年的一线软件开 发经验,他在数所高校进行了多年的软件工程教学实践,总结出了在 16 周的时间内让同学们通过 “做 中学 (Learning By Doing)” 掌握实用的软件工程技术的教学计划,并得到高校师生的积极反馈。在此 ......一起来看看 《构建之法(第三版)》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具