iOS日历、NSCalendar初探(基础篇)。

作者: cocoaAhda | 来源:发表于2017-01-13 20:44 被阅读8585次
城市有我奋斗的青春.jpg

######先说下需求:选择日期弹出日历(跟途牛,携程等差不多就行。。。行)

初识NSCalendar到写完日历的感受:

  • 懵+1
  • 什么鬼?
  • 如此强大的日历类
  • 果然利弊都有,虽然很强大,但是极其耗内存
  • 一组表情表示写日历过程中的心情或者每天的心情(同意的猿/媛点赞):


    我的一天.png

先来点湿的(很湿很能吹...)

NSCalendar官方API:
NSCalendar objects encapsulate information about systems of reckoning time in which the beginning, length, and divisions of a year are defined. They provide information about the calendar and support for calendrical computations such as determining the range of a given calendrical unit and adding units to a given absolute time

NSCalendar的初始化方法:
常用:

// 可指定日历的算法
NSCalendar  * calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
>// currentCalendar取得的值会一直保持在cache中,第一次取得以后如果用户修改该系统日历设定,这个值也不会改变。
NSCalendar  * calendar = [NSCalendar currentCalendar];
//如果用autoupdatingCurrentCalendar,那么每次取得的值都会是当前系统设置的日历的值。 
NSCalendar  * autoupdatingCurrent = [NSCalendar autoupdatingCurrentCalendar];
//- initWithCalendarIdentifier:
 //如果想要用公历的时候,就要将NSDateFormatter的日历设置成公历。否则随着用户的系统设置的改变,取得的日期的格式也会不一样。
    NSCalendar *initCalendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
    [formatter setCalendar:initCalendar];

NSCalendar官方API翻译:

NSCalendar对象封装了有关计算时间的系统的信息,其中定 义了年的开始,长度和分割。它们提供关于日历的信息和对日历计算的支持,例如确定给定的日历单元的范围和将单位添加到给定的绝对时间

由此能理解数学英语都辣鸡的我看到它有多懵,NSCalendar功能很强大,还有一点就是我写完日历后,界面会非常卡。最终发现是这个NSCalendar特别特别耗内存。最好能写成全局变量来使用。

是时候来点干的了(聊一些我工作用到的类和一些封装的方法)

先上效果图瞅瞅(类似途牛的日历,没有选择后标记):

calendarTop.png
calendarBottom.png

<p>1.获取当前月份有多少天:</p>

-(NSInteger)getCurrentMonthForDays{
    // 创建一个日期类对象(当前月的calendar对象)
    NSCalendar *calendar = [NSCalendar currentCalendar];
    // NSRange是一个结构体,其中location是一个以0为开始的index,length是表示对象的长度。他们都是NSUInteger类型。
    NSRange range = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:[NSDate date]];
    NSUInteger numberOfDaysInMonth = range.length;
   return numberOfDaysInMonth;
}

<p>2获取目标月份的天数:</p>

 -(NSInteger)getNextNMonthForDays:(NSDate)date
{
    NSCalendar * calendar = [NSCalendar currentCalendar];
    // 调用rangeOfUnit方法:(返回一样是一个结构体)两个参数一个大单位,一个小单位(.length就是天数,.location就是月)
    NSInteger monthNum = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:date].length;
    return monthNum;
}

<p>3.获取一个目标date(包含某个月的1号数据),或者说获取某个月的1号的date对象</p>

    -(NSDate *)getAMonthframDate:(NSDate*)date {
    // 指定日历单位,如日期和月份。(这里指定了年月日,还有其他字段添加单位.特别齐全 :世纪,年月日时分秒等等等)
    NSCalendarUnit dayInfoUnits  = NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
    // NSDateComponents封装了日期的组件,年月日时分秒等(个人感觉像是平时用的model模型)
    NSDateComponents *components = [calendar components: dayInfoUnits fromDate:date];
    // 指定1号
    components.day = 1;
    // 指定月份(我这里是获取当前月份的下1个月的1号的date对象,所以用的++,其上个月或者其他同理)
    components.month++;
    // 转成需要的date对象return
    NSDate * nextMonthDate =[calendar dateFromComponents:components];
    return nextMonthDate;
}
(用到的API基本注释完了下边就不那么多注释了)纯属个人理解,如发现错误的地方请指正,大家共同进步.

<p>
</p>
<p>4.获取某个月的1号是星期几(必不可少的一个方法,用来布局UI使每月1号与星期队形起来):</p>

-(NSInteger)getFirstDayWeekForMonth:(NSDate*)date
{
    // NSCalendarIdentifierGregorian : 指定日历的算法
    NSCalendar * calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    // NSDateComponents封装了日期的组件,年月日时分秒等(个人感觉像是平时用的model模型)
    // 调用NSCalendar的components:fromDate:方法返回一个NSDateComponents对象
    // 需要的参数分别components:所需要的日期单位 date:目标月份的date对象
    NSDateComponents *comps = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond|NSCalendarUnitWeekday fromDate:date];
    NSLog(@"NSDateComponents是这个样子的:%@",comps);
    // 直接调用自己weekDay属性
    NSInteger weekday = [comps weekday];
    #warning mark --找了很多原因不知道为什么星期数总是比实际快一天,有时间找更好的解决方法(暂时用-1天处理了)
    weekday--;
    NSLog(@"[comps weekday] = %ld",(long)weekday);
    if (weekday == 7) {
        return 0;
    }else return weekday;
}

<p>5. 当前时间与之前时间的间隔:</p>

/**
 *  @author jaki, 15-09-21 17:09:42
 *  @brief  获取一个标准时间戳与当前时间的时间差
 *  @param tinterval 时间戳
 *  @return 距离当前时间的时间间隔
 */
-(NSString *)getStandardTimeInterval:(NSTimeInterval)interval{
    //进行时间差比较
    //当前时间与1970时间戳(秒为单位)
    NSTimeInterval time = [[NSDate date] timeIntervalSince1970];
    // 当前时间戳-当时时间戳=差值(比如朋友圈动态发表时间为10分钟前(当前时间-发表时间))
    NSTimeInterval timeInterval = time-interval;
    //计算出天、小时、分钟
    int day = timeInterval/(60*60*24);
    int hour = ((long)timeInterval%(60*60*24))/(60*60);
    int minite = ((long)timeInterval%(60*60*24))%(60*60)/60;
    NSMutableString * timeStr = [[NSMutableString alloc]init];
    // 逻辑判断
    if (day!=0) {
        [timeStr appendString:[NSString stringWithFormat:@"%d天前",day]];
    }else{
        if (hour!=0) {
            [timeStr appendString:[NSString stringWithFormat:@"%d小时前",hour]];
        }else{
            if (minite<1) {
                [timeStr appendString:@"刚刚"];
            }else{
                [timeStr appendString:[NSString stringWithFormat:@"%d分钟前",minite]];
            }
        }
    }
    return timeStr;
}

<p>6.获取当前系统时间:</p>

-(NSString *)getCurrentTime{
    NSDateFormatter * formatter = [[NSDateFormatter alloc]init];
    <code>// 格式化系统时间字符串</code>
    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSString * time = [formatter stringFromDate:[NSDate date]];
    return time;
}

<p>7.返回年月日时分秒:</p>

<code>#pragma mark --- 对比上边就比较简单了不过多啰嗦</code>
-(int)getYear{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSUInteger unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    NSDateComponents *dateComponent = [calendar components:unitFlags fromDate:self];
    return (int)dateComponent.year;
    
}
-(int)getMonth{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSUInteger unitFlags =  NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    NSDateComponents *dateComponent = [calendar components:unitFlags fromDate:self];
    return (int)dateComponent.month;
}
-(int)getDay{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSUInteger unitFlags =  NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    NSDateComponents *dateComponent = [calendar components:unitFlags fromDate:self];
    return (int)dateComponent.day;
}
-(int)getHour{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSUInteger unitFlags =  NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    NSDateComponents *dateComponent = [calendar components:unitFlags fromDate:self];
    return (int)dateComponent.hour;
}
-(int)getMinute{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSUInteger unitFlags =  NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    NSDateComponents *dateComponent = [calendar components:unitFlags fromDate:self];
    return (int)dateComponent.minute;
}
-(int)getSecond{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSUInteger unitFlags =  NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    NSDateComponents *dateComponent = [calendar components:unitFlags fromDate:self];
    return (int)dateComponent.second;
}

<p>8.date对象NSString互相转换:</p>

// date对象转换成字符串(最后return根据自己需求处理)
-(NSString * )theTargetDateConversionStr:(NSDate * )date
{
    NSDateFormatter* dateFormat = [[NSDateFormatter alloc] init];//实例化一个NSDateFormatter对象
    [dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];//设定时间格式,这里可以设置成自己需要的格式
    NSString *currentDateStr = [dateFormat stringFromDate:date];
    // 根据自己需求处理字符串
    return [currentDateStr substringToIndex:7];
}
// NSString对象转date
-(NSDate* )theTargetStringConversionDate:(NSString *)str
{
    //设置转换格式
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSDate *date=[formatter dateFromString:str];
    return date;
}
8个方法差不多能够实现一个简单点的日历控件了,88大发,大功告成。2017第一篇,比较偏基础适合我这种菜鸟或者新手,大神路过的话就当娱乐一下了。有错误的话希望多多指点楼主一下

下面贴一下代码以及实现思路:

思路:

刚知道要写日历的时候是懵逼的,对NSdate还好、NSCalendar完全没有概念。查了挺多资料,也在github找了好几个demo想直接拿过来用,不过不太合适所以决定自己写。试了tableView、跟colelctionView,最后选择collectionView需求是展示当前月跟之后三个月的日历。

所以就:

区头实现星期View->四个分区->区头区尾配合实现效果,上边聊得几个方法处理DataSource.

日历中标记今天的思路是:

实例变量selectedIndex(今天的下标): ---实现->(获取到今天几号,加上今天周几-1就是日历中今天那个cell所在的位置了)

直接截图代码:

都比较基础(自己保存下笔记,也分享给能用到的童鞋)

UICollectionView实现:


collectionView.png

DataSource:每个分区返回item数量


dataSource返回item个数.png

DataSource: 绘制item

dateSource绘制Cell.png

DataSource:headerView和footerView以及点击回传数据:


区头、区尾、点击.png

demo地址:https://github.com/rundonkey/DzNSCalendar.git

到这我的这个懵逼写日历的过程就完毕了
Bug神在上请保佑所有正在奋斗的90后程序猿们2017永无bug,保佑老猿们步步高升顺顺利利!

相关文章

  • iOS日历、NSCalendar初探(基础篇)。

    ######先说下需求:选择日期弹出日历(跟途牛,携程等差不多就行。。。行) 初识NSCalendar到写完日历的...

  • iOS 日历 NSCalendar

    NSCalendar 是 iOS 获取日历数据的工具类。 获取指定月份的天数: 获取指定日期的是周几,在 NSCa...

  • iOS日历(NSCalendar)

    代理 Block两种回调方式 collectionStyle 设置 横向 竖向 两种日历 demo通道

  • 面试准备第九篇

    ```日历 NSCalendar *calendar = [[NSCalendar alloc] initWith...

  • iOS 日历类(NSCalendar)

    对于时间的操作在开发中很常见,但有时候我们需要获取到一年后的时间,或者一周后的时间.靠通过秒数计算是不行的.那就牵...

  • iOS NSCalendar 日历【转】

    NSCalendar 对世界上现存的常用的历法进行了封装,既提供了不同历法的时间信息,又支持日历的计算。可以很方便...

  • 时间与日期

    在iOS原生类中用以处理时间与日期的类:NSCalendar 日历处理NSDateComponents 将日期进...

  • NSCalendar日历

    http://www.cnblogs.com/wujian1360/archive/2011/09/05/2168...

  • 日历NSCalendar

    日历 某一天- (NSInteger)day:(NSDate *)date{NSDateComponents *c...

  • NSCalendar 日历

    通常我们计算时间差,都是这么算的 现在我用一种新的方法来计算时间差 就是NSCalendar 打印出来的就是相差...

网友评论

  • 零壹后学者:星期数比实际快一天是因为西方以周日为一周的开始:smile:
  • 程序猿界的cai渣渣:item 复用问题没有解决,任意选中一个 上滑 就会出现 多个选中状态(黄色)
  • 心语风尚:怎么获取系统的节日 知道是那个 api 单不知道怎么用
    王_胖胖:@心语风尚 如何解决的?
    心语风尚:@cocoaAhda 现在解决了 谢谢
    cocoaAhda:@心语风尚 发下类名
  • 心语风尚:节日怎么获取
  • 心语风尚:怎么获取节日 获取系统的日历 没有节日
  • 超_iOS:-(int)getDay{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSUInteger unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    NSDateComponents *dateComponent = [calendar components:unitFlags fromDate:self];
    return (int)dateComponent.day;
    }
    这个方法获取的是哪里的时间啊?貌似不是系统时间
    超_iOS:@cocoaAhda 恩我也试了,反正不是北京时间.我现在想判断是不是在同一天
    cocoaAhda:2017-11-24 11:44:44.145830+0800 Test[47451:2289029] 获取今天:<NSDateComponents: 0x60000014ac90>
    Calendar Year: 2017
    Month: 11
    Leap month: no
    Day: 24
    Hour: 11
    Minute: 44
    Second: 44
    是的吧 ,我刚测试了一下。
  • fc64068ec553:月数多了会卡
  • fc64068ec553:貌似没有重用啊
  • 只是个少年:楼主可以转载吗,会表明出处的:smile:
    cocoaAhda:@只是个少年 不表也没事:smile:
  • 风雨落山岚::blush: :blush:
    cocoaAhda:@风雨落山岚 :smile:
  • 菊上一枝梅:必须给你一个大大的赞👍
    cocoaAhda:@Regret_V 有用就行:smile:
  • 爱新觉罗fate:楼主,请教一下,有没有获得当前时间的上周六的日期的方法啊?
    cocoaAhda:@爱新觉罗fate 应该是可以自己去算的,你什么需求呢?
  • shensir_aye:因为美国时间 是从周日为第一天的
    cocoaAhda:@大大大大大大 666
  • 妖精的菩萨:建议把根据indexPath做switch语句封装一下,可以适应更多月份的处理哈。辛苦了楼主。
    cocoaAhda:@妖精的菩萨 知道了 谢谢建议。
  • zero000:大神,求demo 1915853255@qq.com
    cocoaAhda:@zero000 下边有下载地址
  • 木子尚武:楼主可以把Demo放到github上
    cocoaAhda:@木子尚武 嗯呢,最近有点忙,以后的放。
  • 棍武中原:楼主QQ加不上啊
    棍武中原:@rundonkeyZ 你加我吧,1058332475
    cocoaAhda:@棍武中原 QQ 没有错啊 不行我

本文标题:iOS日历、NSCalendar初探(基础篇)。

本文链接:https://www.haomeiwen.com/subject/vdjsbttx.html