获取农历、事件、节假日、节气等信息,可以通过NSCalendar
和EventKit
完成。
一. 农历提供者NSCalendar
- 创建农历版NSCalendar。
@property (strong, nonatomic) NSCalendar *chineseCalendar;
self.chineseCalendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierChinese];
最常用的公立标识符是NSCalendarIdentifierGregorian
, 此处使用NSCalendarIdentifierChinese
表示农历。
- 获取农历日期的方法
NSInteger lunarDay = [self.chineseCalendar component:NSCalendarUnitDay fromDate:date];
变量lunarDay
即为date对象对应的农历日期,如1代表初一
。但是我们通常不会将阿拉伯数字展示到日历,需要自己转换。
@property (strong, nonatomic) NSArray *lunarChars;
self.lunarChars = @[@"初一",@"初二",@"初三",@"初四",@"初五",@"初六",@"初七",@"初八",@"初九",@"初十",@"十一",@"十二",@"十三",@"十四",@"十五",@"十六",@"十七",@"十八",@"十九",@"二十",@"二一",@"二二",@"二三",@"二四",@"二五",@"二六",@"二七",@"二八",@"二九",@"三十"];
NSString *lunarDayString = self.lunarChars[day-1];
变量lunarDayString
即为当前对应的农历字符串,如初一、初二、三十
等。
二. 事件、节气、节假日提供者EventKit
通过EventKit
可以读取系统日历的内置事件,需要日历权限,但避免了搜索和引入三方农历框架的麻烦。
#import
@property (strong, nonatomic) NSArray *events;
__weak typeof(self) weakSelf = self;
EKEventStore *store = [[EKEventStore alloc] init];
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if(granted) {
NSDate *startDate = self.minimumDate; // 开始日期
NSDate *endDate = self.maximumDate; // 截止日期
NSPredicate *fetchCalendarEvents = [store predicateForEventsWithStartDate:startDate endDate:endDate calendars:nil];
NSArray *eventList = [store eventsMatchingPredicate:fetchCalendarEvents];
NSArray *events = [eventList filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(EKEvent * _Nullable event, NSDictionary * _Nullable bindings) {
return event.calendar.subscribed;
}]];
weakSelf.events = events;
}];
此处eventList
变量即为开始日期startDate
到截止日期endDate
之间的所有事件,而events
变量只包含订阅事件,如春节、劳动节、圣诞节、夏至
等,排除了用户在系统日历中自己添加的事件,如某某人的生日等。
模拟器环境的系统日历中没有包含农历、节假日等订阅事件,请在真机下运行。
三、将农历文字、事件展示到FSCalendar
基础的UI搭建请参考第一篇Hello World.
1、 实现-calendar:subtitleForDate:
为对应的日期设置副标题,返回值可以是任意NSString对象。
- (NSString *)calendar:(FSCalendar *)calendar subtitleForDate:(NSDate *)date
{
EKEvent *event = [self eventsForDate:date].firstObject;
if (event) {
return event.title; // 春分、秋分、儿童节、植树节、国庆节、圣诞节...
}
NSInteger day = [_lunarCalendar component:NSCalendarUnitDay fromDate:date];
return _lunarChars[day-1]; // 初一、初二、初三...
}
// 某个日期的所有事件
- (NSArray *)eventsForDate:(NSDate *)date
{
NSArray *filteredEvents = [self.events filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(EKEvent * _Nullable evaluatedObject, NSDictionary * _Nullable bindings) {
return [evaluatedObject.occurrenceDate isEqualToDate:date];
}]];
return filteredEvents;
}
效果:
若要自定义日期文字,实现-calendar:titleForDate:
即可。例如让当日的文字显示今天
。
@property(strong, nonatomic) NSCalendar *gregorianCalendar;
self.gregorianCalendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
- (NSString *)calendar:(FSCalendar *)calendar titleForDate:(NSDate *)date
{
if ([self.gregorianCalendar isDateInToday:date]) {
return @"今天";
}
return nil;
}
3、添加事件圆点, 实现-calendar:numberOfEventsForDate:
- (NSInteger)calendar:(FSCalendar *)calendar numberOfEventsForDate:(NSDate *)date
{
NSArray *events = [self eventsForDate:date];
return events.count;
}
-calendar:numberOfEventsForDate:方法
最大支持3个圆点。使用-calendar:imageForDate:
可以代替为任意图片样式,返回值为UIImage
对象。
效果:
使用
[calendar reloadData]
会使所有数据源及样式重新加载,适用于异步加载。
项目主页:https://github.com/WenchaoD/FSCalendar
QQ支持群: 323861692