因为项目需要,上github找了不少日历控件,最终敲定了MaterialCalendarView。



首先昵,要说下开源控件使用的好处,我感觉大致有以下几个方面:



1).网上有现成的为啥不去用,你觉得你自己写的比别人牛逼吗?



2).涉及年月日日期处理,滚动事件,相互交错,没有紧密的逻辑思维去构架,肯定漏洞百出,想想数不尽的bug,不寒而栗。



3).最关键的是,我懒,我懒,我懒!自己写费时费力,牛逼的日历组件都可以做一个app了,再说我只是想要一个选择日期功能。





说了一堆废话,现在我们来分析源码了。。。。。



老外写的东西层次感还是很分明的,我大致给它分为三个部分:日期的格式化,自定义的span效果,以及日历控件的实现。不用说日历实现是最重要的一部分了,我们由简入繁,从日期分析开始。

1)format,顾名思义,格式化,达到我们想要的日期展示样式。

format包中有八个java文件,其中有三个接口,五个实现类。

三个接口:

  • DayFormatter 通过自定义的CalendarDay对象,得到一个日期的字符串标签。其实现类是DateFormatDayFormatter。
  • TitleFormatter 通过自定义的CalendarDay对象,得到一个包含年月的字符串标签,作为MaterialCalendarView的标签。其实现类为DateFormatTitleFormatter和MonthArrayTitleFormatter。
  • WeekDayFormatter 将一个日期中Calendar.DAY_OF_YEAR对应的值转换成一个字符串标签。其实现类是ArrayWeekDayFormatter。

这三个接口都只有一个方法,有的提供了一个公有的默认实现类。其功能就是将日期的数值转换成本地化的可读字符串。在这里我可以想到的是,因为使用了接口,我们可以很灵活的替换其实现类,而不用更改日历控件中的代码,实现定制化的需求。

2)span

spans包中只有一个类DotSpan,实现了在文字下方画一个小圆点的效果。这是一个示例,我们可以模仿它来实现自己想要的效果。比如,如果想在日期的下方用一行小字显示,用span是很方便的一种实现方式。



3)MaterialCalendarView



这个包中有16个Java文件,是此开源控件主要的代码所在。其中,组合成最终控件的四个最重要的类是DayView,WeekDayView,MonthView和MaterialCalendarView。

  1. DayView 继承自CheckedTextView。之所以用CheckedTextView而不是TextView,是为了使用android.R.attr.state_checked状态,在日期被选中时显示不同的背景图片。
  2. WeekDayView 继承自TextView,用于在日历的第一排显示星期的标签。
  3. MonthView 继承自ViewGroup,它包含7个WeekDayView和42个DayView,即一个7*7的矩形,其中每一个矩形称为一个tile。
  4. MaterialCalendarView 继承自ViewGroup,包含上方的title和下方的ViewPager。这个控件的宽度如果不能被7整除,那么它会自动缩小其内容,并居中。

MaterialCalendarView层次感非常强烈,注释清楚,本人愚钝啊,时刻不丢粗心的毛病,改造日历期间很多功能点找不到,修改日历的disable事件,点击效果,日历字体大小。。。。。等等。好了,废话不多说,先来一份改造好的日历图,压压惊!左边是我改造的,右边是我们伟大开源作者的。(提倡开源,一直很欣赏这些懂的分享的人,只有弱者才会害怕自己的东西被人拿去)


   

android开发之日历框 安卓日历开发_MaterialCalendarView

             

android开发之日历框 安卓日历开发_日历_02

           



左边的日历我针对自己项目进行了定制设计,调节了日历大小,之前的dayview是宽高等比大小,宽度是平分屏幕,所以这样导致高度很高,相互之间间隔比较大,我通过monthview的onMeasure方法,将高度修改为

int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
        (int)(measureTileSize*0.65),
        MeasureSpec.EXACTLY
);


这样长宽就3/2了,这个时候只是第一步,仅仅只有monthview大小变了,整体的view大小还没有变,所以我们还要处理下MaterialCalendarView的onMeasure 方法,对整体高度进行修改


int measuredHeight = (int)(measureTileSize*0.7) * viewTileHieght;