最近App需要一个日历显示界面,找了一下发现EPCalendarPicker库比较合适。
简单看了一下它的源代码,发现其简单,小巧,虽然界面可定制能力一般。
我的App不需要使用日期的选择功能,只需要显示功能。它的界面对于我来说基本满足,不需要再进行太大的涂修,所以可定制有限也勉强够用了。
不过EPCalendarPicker对于我的项目来说有几个需要改进的地方:
- 它只能初始化成startYear到endYear之间的整年日期;而我需要精细到某个月
- 它的界面都是英文;而我需要根据不同语言自动进行切换
- 它的选择日期的颜色是可以用户修改的,但只能是相同的;而我需要不同日期有不同的选择颜色
我看了一下EPCalendarPicker作者有近1年没更过了,找作者估计也是没戏了。所以我们主要就以上3点自己做一下修改。有的修改很简单,有的稍微困难点;但不管怎样总体难度都不会太高,请跟随本猫,顺其自然 ;)
一.创建精确到月
打开EPCalendarPicker.swift文件发现其最具体最复杂的初始化器是:
public init(startYear: Int, endYear: Int, multiSelection: Bool, selectedDates: [Date]?)
查看相关源代码可以发现,默认初始月都是1月。因为我们需要精确到指定月,所以首先需要增加2个实例属性:
fileprivate(set) open var startYear: Int
fileprivate(set) open var endYear: Int
fileprivate(set) open var startMonth: Int //New
fileprivate(set) open var endMonth: Int //New
为了为它们赋值,需要增加一个新的初始化器:
public init(startYear: Int, startMonth: Int, endYear: Int, endMonth: Int, multiSelection: Bool, selectedDates: [Date]?)
把之前初始化器中的内容原封不动的拷贝进来,并增加对startMonth和endMonth的赋值代码。同时将原来的初始化器内容修改为:
public convenience init(startYear: Int, endYear: Int, multiSelection: Bool, selectedDates: [Date]?) {
self.init(startYear: startYear, startMonth: 1, endYear: endYear, endMonth: 1, multiSelection: multiSelection, selectedDates: selectedDates)
}
注意初始化器名称要增加convenience修饰。
当然光改添加2个实例属性是不够的,我们还得深入到调用逻辑中去,遍历该类将:
let startDate = Date(year: startYear, month: 1, day: 1)
代码替换为:
let startDate = Date(year: startYear, month: startMonth, day: 1)
因为每个Section代表一个月,所以原来Section的属性总是12的整倍数。但现在精确到了月,所以Section的数量就发生了变化,定位到如下方法:
override open func numberOfSections(in collectionView: UICollectionView) -> Int
将其中对于Section数量的算法做一下替换:
//let numberOfMonths = 12 * (endYear - startYear) + 12
//上面一句替换为如下一句
let numberOfMonths = (12 - startMonth + 1) + (endYear - startYear - 1) * 12 + endMonth
EPCalendarPicker类中有一个滚动到当前日的实例方法,因为月的数量发生了变化,所以我们需要重写该实例方法:
open func scrollToToday () {
let today = Date()
scrollToMonthForDate(today)
}
open func scrollToMonthForDate (_ date: Date) {
let month = date.month()
let year = date.year()
//重新计算section的索引
let section = ((year - startYear) * 12) + month - startMonth + 1
let indexPath = IndexPath(row:1, section: section-1)
self.collectionView?.scrollToIndexpathByShowingHeader(indexPath)
}
最后我们需要对传入的年和月做合法验证,在如下方法中添加一段代码:
override open func numberOfSections(in collectionView: UICollectionView) -> Int{
if startYear > endYear {
return 0
}
//添加如下一句
if startYear == endYear,startMonth > endMonth{
return 0
}
//省略无关代码...
}
OK,现在我们就可以使用新的初始化器,创建EPCalendarPicker精确到起始月和结束月了,虽然很累,但看一下成果,还是很有成就感的嘛 :)
以下是2016.5到2017.1的日历界面: