授权转载,作者:codingZero(简书)
不啰嗦,直接上思路。
时间选择就不说了,界面固定的,说说日期选择。
日期选择其实就是一个collectionView,collectionView的item数量,取决与日历的开始日期与结束日期。
假设开始日期为1970-01-01,结束日期为当前日期
那item的数量 = 当前日期与开始日期相差的天数 + 1 + 4(1970-01-01是星期四),为什么要+1,自己领悟,如图
接下来就是cell的赋值,其实这个也是非常简单的,代码如下,开始日期是星期几就从第几个cell开始赋值(星期日是第0个)。开始日期+indexPath.item - 开始日期的星期,就能得到该cell对应的日期,然后将日期中的多少号显示在cell上就行了,如果是1号,就把月份也显示出来
if (indexPath.item >= _firstWeekday) { item.date = [DateTool date:self.startDate addDays:indexPath.item - _firstWeekday]; } else { item.date = nil; }
cell中的代码
- (void)setDate:(NSDate *)date { _date = date; if (!date) { _monthLabel.text = @""; _dayLabel.text = @""; return; } NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:date]; if (components.day == 1 || [[NSCalendar currentCalendar] isDateInToday:date]) { _monthLabel.text = [NSString stringWithFormat:@"%@", self.months[components.month - 1]]; } else { _monthLabel.text = @""; } _dayLabel.text = [NSString stringWithFormat:@"%ld", components.day]; }
上面说的这些都挺简单的,接下来说说下面这个功能的实现,如图
滚动collectionView的时候,上面会出现对应的年份与月份,笔者的做法是,collectionView上面叠加了一个tableview,滚动collectionView的同时,同步滚动tableview。
这里的难点就在于同步,如何保证tableview上的日期与collectionView上的日期正好对应上,进一步说,难点在于tableviewCell高度的计算,把tableviewCell的高度计算对了,剩下的就简单了
Cell高度的计算
其实在做之前,笔者也觉得这个高度的计算一定很难,但是有了思路之后,发觉还是非常简单的,只要你不是数学白痴,就能看懂
以下面的图为例:
我们先看第一个cell,这个cell的高度为collectionView中3个item的高度。
这个3是怎么算出来的?很简单,开始日期我们知道,那我们就可以取出开始月份的最后一天,这里是1974-11-30,然后我们计算出这个日期与开始日期相差的天数 + 1 + 6(开始日期是周六),然后(天数 + 6)/ 7,取整就可以得到3了,不要问我为什么+6。
第二个cell高度的计算也类似,不过这需要依赖第一个cell的高度,我们在开始日期的基础上+1个月,取出这个月最后一天的日期并计算与开始日期相差的天数,然后算出总高度,再用这个高度减去上一个cell的高度,就可以得到第二个cell的高度了。
后面的以此类推,最后一个略有不同,最后一个月不能取最后一天的日期,而是要取结束日期
这样计算出来的cell的总高度最终与collectionView的contentSize.height是一样的,所以要保证同步,只需要在滚动collectionView的时候,设置tableview的垂直偏移量与collectionView的一致就行了
结束语
表达的可能不是很清楚,有兴趣研究的可以到笔者的Github下载!地址:https://github.com/codingZero/XRCalendarView。