本篇文章主要介绍一下我在自定义日历这个Demo中所用到的系统类库和第三方类库以及遇到的一些问题
使用到的类库
系统类库EventKitUI.framework 和 EventKit.framework
第三方类库SSLunarDate
SSLunarDate 可以通过CocoaPods进行安装 pod ‘SSLunarDate’, ‘~> 0.0.1’,也可以点击链接下载:SSLunarDate主要功能
●通过UICollectionView实现日历显示,(包括公历,农历的显示,部分节日的显示)
●同过调用EKEventEditViewController可添加事件到日历,并在日历中有所提示
●通过调用EKEventViewController可编辑修改日历事件EKEventEditViewController和EKEventViewController都是系统界面,用起来很方便可以节省很多开发时间,最终的效果也很不错
## 主要代码 ##
/**
* 获取当前月的年份
*/
- (NSInteger)currentYear:(NSDate *)date{
NSDateComponents *componentsYear = [[NSCalendar currentCalendar] components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:date];
return [componentsYear year];
}
/**
* 获取当前月的月份
*/
- (NSInteger)currentMonth:(NSDate *)date{
NSDateComponents *componentsMonth = [[NSCalendar currentCalendar] components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:date];
return [componentsMonth month];
}
/**
* 获取当前是哪一天
*
* @param date <#date description#>
*
* @return <#return value description#>
*/
- (NSInteger)currentDay:(NSDate *)date{
NSDateComponents *components = [[NSCalendar currentCalendar] components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:date];
return [components day];
}
/**
* 本月又几天
*
* @param date <#date description#>
*
* @return <#return value description#>
*/
- (NSInteger)currentMonthOfDay:(NSDate *)date{
NSRange totaldaysInMonth = [[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:date];
return totaldaysInMonth.length;
}
/**
* 本月第一天是星期几
*
* @param date <#date description#>
*
* @return <#return value description#>
*/
- (NSInteger)currentFirstDay:(NSDate *)date{
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setFirstWeekday:2];//1.mon
NSDateComponents *comp = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:date];
[comp setDay:1];
NSDate *firstDayOfMonthDate = [calendar dateFromComponents:comp];
NSUInteger firstWeekday = [calendar ordinalityOfUnit:NSCalendarUnitWeekday inUnit:NSCalendarUnitWeekOfMonth forDate:firstDayOfMonthDate];
return firstWeekday - 1;
}
/**
* 获取对应的农历
*
* @param date <#date description#>
*
* @return <#return value description#>
*/
- (SSLunarDate *)lunarDaysIntDay:(int)nowIndex{
NSDateComponents * components = [[NSDateComponents alloc] init];
components.year = [_year integerValue];//[self currentYear:_date];
components.month = [_month integerValue];//[self currentMonth:_date];
components.day = nowIndex;
NSCalendar * calendar = [NSCalendar currentCalendar];
NSDate *date = [calendar dateFromComponents:components];
SSLunarDate *lunar = [[SSLunarDate alloc] initWithDate:date];
return lunar;
}
----------
/**
* 创建collectionView
*/
-(void)createCollectionView
{
//设置流水布局
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init];
layout.itemSize = CGSizeMake(SCREEN_WIDTH / 7, SCREEN_WIDTH / 7);
layout.minimumLineSpacing = 0.0;
layout.minimumInteritemSpacing = 0.0;
//创建collectionView
_mainCollectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 60, SCREEN_WIDTH, SCREEN_WIDTH) collectionViewLayout:layout];
_mainCollectionView.backgroundColor = [UIColor clearColor];
[self.view addSubview:_mainCollectionView];
//注册cell
[_mainCollectionView registerClass:[CalendarCell class] forCellWithReuseIdentifier:@"cell"];
//指定代理
_mainCollectionView.delegate = self;
_mainCollectionView.dataSource = self;
//注册heaerView 此处的ReuseIdentifier 必须和 cellForItemAtIndexPath 方法中 一致 均为reusableView
[_mainCollectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"cell"];
}
----------
/**
* 添加事件
*/
-(void)add
{
EKEventEditViewController *addController = [[EKEventEditViewController alloc] init];
addController.eventStore = _eventStore;
addController.editViewDelegate = self;
[self presentViewController:addController animated:YES completion:nil];
}
//点击保存或取消的回调方法
#pragma mark - EKEventEditViewDelegate
- (void)eventEditViewController:(EKEventEditViewController *)controller
didCompleteWithAction:(EKEventEditViewAction)action
{
CalendarController * __weak weakSelf = self;
[self dismissViewControllerAnimated:YES completion:^
{
if (action != EKEventEditViewActionCanceled)
{
dispatch_async(dispatch_get_main_queue(), ^{
UILabel *label = (UILabel *)[self.view viewWithTag:100];
[weakSelf getCalendarEvent:label.text];
});
}
}];
}
----------
/**
* 获取日历事件
*
* @param start 开始时间
* @param end 结束时间
*/
-(void)getCalendarEvent:(NSDate *)start last:(NSDate *)end
{
//获取事件时间段内的事件
NSPredicate *predicate = [_eventStore predicateForEventsWithStartDate:start
endDate:end
calendars:nil];
NSArray *array = [_eventStore eventsMatchingPredicate:predicate];
for (EKEvent *event in array) {
EKCalendar *calendar = event.calendar;
if (calendar.type == EKCalendarTypeLocal) {
if (!_events) {
_events = [[NSMutableArray alloc]init];
}
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:@"yyyy/MM/dd"];
[formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT+8"]];
NSString *start = [formatter stringFromDate:event.startDate];
NSString *end = [formatter stringFromDate:event.endDate];
NSArray *array = [self dateNumber:start string:end];
for (int i = 0; i < array.count; i++) {
if (![_events containsObject:[array objectAtIndex:i]]) {
[_events addObject:[array objectAtIndex:i]];
}
}
}
}
dayCurrect = 1;
[_mainCollectionView reloadData];
}
----------
----------
在事件列表页点击列表进入编辑页面
/**
* 点击列表进入事件编辑界面
*
* @param tableView
* @param indexPath
*/
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
EKEventViewController *editEvent = [[EKEventViewController alloc] init];
editEvent.delegate = self;
editEvent.event = [_dataArray objectAtIndex:indexPath.row];
editEvent.allowsEditing = YES;
UINavigationController *nav = [[UINavigationController alloc]
initWithRootViewController:editEvent];
[self presentViewController:nav animated:YES completion:nil];
}
----------
在进入编辑界面时我遇到了一点小的麻烦,在这里简单的说一下
期初位置通过以下方式进入系统提供的编辑界面及EKEventViewController
[self presentViewController:editEvent animated:YES completion:nil];
试了以下导航栏不见了,无法保存或者取消
有尝试了直接push的方法
[self.navigationController pushViewController:editEvent animated:YES];
由于编辑界面有删除功能,在界面底部,似乎是个UITabBar,只要出现了在那个界面都不会消失
最终经过尝试使用现在的方法效果还不错
----------
#pragma mark - EKEventEditViewDelegate
- (void)eventViewController:(EKEventViewController *)controller didCompleteWithAction:(EKEventViewAction)action
{
controller.tabBarController.tabBar.hidden = YES;
EventListController * __weak weakSelf = self;
[self dismissViewControllerAnimated:YES completion:^{
[weakSelf getCalendarEvent:_date last:_end];
}];
}
/**
* 获取日历事件刷新列表
*
* @param start 开始时间
* @param end 结束时间
*/
-(void)getCalendarEvent:(NSDate *)start last:(NSDate *)end
{
//移除数据
[_dataArray removeAllObjects];
//获取事件时间段内的事件
NSPredicate *predicate = [_eventStore predicateForEventsWithStartDate:start
endDate:end
calendars:nil];
NSArray *array = [_eventStore eventsMatchingPredicate:predicate];
for (EKEvent *event in array) {
EKCalendar *calendar = event.calendar;
if (calendar.type == EKCalendarTypeLocal) {
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:@"yyyy/MM/dd"];
[formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT+8"]];
NSString *start = [formatter stringFromDate:event.startDate];
NSString *date = [formatter stringFromDate:_date];
if ([start isEqualToString:date]) {
[_dataArray addObject:event];
}
}
}
[_tableView reloadData];
}
如果有些需求修改以及添加事件需要自定义界面也可通过以下方法完成
//添加事件
EKEventStore* eventStore = [[EKEventStore alloc] init];//获取日历类
EKEvent *event = [EKEvent eventWithEventStore:eventStore];//日历类事件
NSDate *startDate = [[NSDate alloc] init];
NSDate *endDate = [[NSDate alloc] init];
event.title = @"New event test";
event.startDate = startDate;//开始日期
event.endDate = endDate;//结束日期
event.location = @"浙江";//位置
event.allDay = YES;//是否是全天
[event setCalendar:[eventStore defaultCalendarForNewEvents]];
[event addAlarm:[EKAlarm alarmWithRelativeOffset:-30.0f]];
[event addAlarm:[EKAlarm alarmWithRelativeOffset:-15.0f]];
__block NSError *err;
//ios 6之后
if([eventStore respondsToSelector:@selector(requestAccessToEntityType:completion:)]) {
[eventStore requestAccessToEntityType:EKEntityTypeEvent
completion:^(BOOL granted, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (granted) {
[eventStore saveEvent:event span:EKSpanFutureEvents commit:YES error:&err];
} else {
NSLog(@"不允许访问日历");
}
});
}];
} else {
//ios4,5
[eventStore saveEvent:event span:EKSpanThisEvent error:&err];
}
//修改事件 对事件进行延时操作
-(void)loadEvent{
EKEventStore *store = [[EKEventStore alloc] init];
if ([store respondsToSelector:@selector(requestAccessToEntityType:completion:)])
{
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error)
{
if ( granted )
{
NSLog(@"User has granted permission!");
}
else
{
NSLog(@"User has not granted permission!");
}
}];
}
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *oneDayAgoComponents = [[NSDateComponents alloc] init];
oneDayAgoComponents.day = -2;
NSDate *oneDayAgo = [calendar dateByAddingComponents:oneDayAgoComponents
toDate:[NSDate date]
options:0];
NSDateComponents *oneYearFromNowComponents = [[NSDateComponents alloc] init];
oneYearFromNowComponents.year = 1;
NSDate *oneYearFromNow = [calendar dateByAddingComponents:oneYearFromNowComponents
toDate:[NSDate date]
options:0];
NSPredicate *predicate = [store predicateForEventsWithStartDate:oneDayAgo
endDate:oneYearFromNow
calendars:nil];
NSArray *events = [store eventsMatchingPredicate:predicate];
NSLog(@"event count:%lu", (unsigned long)[events count]);
for (EKEvent* event in events) {
if ([[event title] hasPrefix:@"My test"]) {
NSArray* alarms = [event alarms];
NSLog(@"title = %@",[event title]);
EKAlarm *alarm = [EKAlarm alarmWithRelativeOffset:6.0f * 10.0f]; // 延时十分钟
NSMutableArray *a = [[NSMutableArray alloc]init];
for (int i = 0; i < alarms.count; i++) {
[a addObject:[alarms objectAtIndex:i]];
}
[a addObject:alarm];
for (int i = 0; i < a.count; i++) {
[event addAlarm:[a objectAtIndex:i]];
}
NSLog(@"-=-=-%@-*-*-*-%@",alarms,a);
NSError *err;
BOOL success = [store saveEvent:event span:EKSpanThisEvent error:&err];
NSLog(@"err%@",[err description]);
NSLog(@"success ? %d",success);
}
}
}
以上就是我在编码过程中的理解以及遇到的问题,下面demo连接
源码连接点击下载
下面是效果图