######先說下需求:選擇日期彈出日歷(跟途牛,攜程等差不多就行。。。行)
初識NSCalendar到寫完日歷的感受:
懵
懵+1
什么鬼?
如此強(qiáng)大的日歷類
果然利弊都有,雖然很強(qiáng)大,但是極其耗內(nèi)存
一組表情表示寫日歷過程中的心情或者每天的心情(同意的猿/媛點(diǎn)贊):

我的一天.png
先來點(diǎn)濕的(很濕很能吹...)
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中,第一次取得以后如果用戶修改該系統(tǒng)日歷設(shè)定,這個值也不會改變。
NSCalendar? * calendar = [NSCalendar currentCalendar];
//如果用autoupdatingCurrentCalendar,那么每次取得的值都會是當(dāng)前系統(tǒng)設(shè)置的日歷的值。
NSCalendar? * autoupdatingCurrent = [NSCalendar autoupdatingCurrentCalendar];
//- initWithCalendarIdentifier:
//如果想要用公歷的時候,就要將NSDateFormatter的日歷設(shè)置成公歷。否則隨著用戶的系統(tǒng)設(shè)置的改變,取得的日期的格式也會不一樣。
NSCalendar *initCalendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
[formatter setCalendar:initCalendar];
NSCalendar官方API翻譯:
NSCalendar對象封裝了有關(guān)計(jì)算時間的系統(tǒng)的信息,其中定? 義了年的開始,長度和分割。它們提供關(guān)于日歷的信息和對日歷計(jì)算的支持,例如確定給定的日歷單元的范圍和將單位添加到給定的絕對時間
由此能理解數(shù)學(xué)英語都辣雞的我看到它有多懵,NSCalendar功能很強(qiáng)大,還有一點(diǎn)就是我寫完日歷后,界面會非常卡。最終發(fā)現(xiàn)是這個NSCalendar特別特別耗內(nèi)存。最好能寫成全局變量來使用。
是時候來點(diǎn)干的了(聊一些我工作用到的類和一些封裝的方法)
先上效果圖瞅瞅(類似途牛的日歷,沒有選擇后標(biāo)記):

calendarTop.png

calendarBottom.png
1.獲取當(dāng)前月份有多少天:
-(NSInteger)getCurrentMonthForDays{
// 創(chuàng)建一個日期類對象(當(dāng)前月的calendar對象)
NSCalendar *calendar = [NSCalendar currentCalendar];
// NSRange是一個結(jié)構(gòu)體,其中l(wèi)ocation是一個以0為開始的index,length是表示對象的長度。他們都是NSUInteger類型。
NSRange range = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:[NSDate date]];
NSUInteger numberOfDaysInMonth = range.length;
return numberOfDaysInMonth;
}
2獲取目標(biāo)月份的天數(shù):
-(NSInteger)getNextNMonthForDays:(NSDate)date
{
NSCalendar * calendar = [NSCalendar currentCalendar];
// 調(diào)用rangeOfUnit方法:(返回一樣是一個結(jié)構(gòu)體)兩個參數(shù)一個大單位,一個小單位(.length就是天數(shù),.location就是月)
NSInteger monthNum = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:date].length;
return monthNum;
}
3.獲取一個目標(biāo)date(包含某個月的1號數(shù)據(jù)),或者說獲取某個月的1號的date對象
-(NSDate *)getAMonthframDate:(NSDate*)date {
// 指定日歷單位,如日期和月份。(這里指定了年月日,還有其他字段添加單位.特別齊全 :世紀(jì),年月日時分秒等等等)
NSCalendarUnit dayInfoUnits? = NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
// NSDateComponents封裝了日期的組件,年月日時分秒等(個人感覺像是平時用的model模型)
NSDateComponents *components = [calendar components: dayInfoUnits fromDate:date];
// 指定1號
components.day = 1;
// 指定月份(我這里是獲取當(dāng)前月份的下1個月的1號的date對象,所以用的++,其上個月或者其他同理)
components.month++;
// 轉(zhuǎn)成需要的date對象return
NSDate * nextMonthDate =[calendar dateFromComponents:components];
return nextMonthDate;
}
(用到的API基本注釋完了下邊就不那么多注釋了)純屬個人理解,如發(fā)現(xiàn)錯誤的地方請指正,大家共同進(jìn)步.
4.獲取某個月的1號是星期幾(必不可少的一個方法,用來布局UI使每月1號與星期隊(duì)形起來):
-(NSInteger)getFirstDayWeekForMonth:(NSDate*)date
{
// NSCalendarIdentifierGregorian : 指定日歷的算法
NSCalendar * calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
// NSDateComponents封裝了日期的組件,年月日時分秒等(個人感覺像是平時用的model模型)
// 調(diào)用NSCalendar的components:fromDate:方法返回一個NSDateComponents對象
// 需要的參數(shù)分別components:所需要的日期單位 date:目標(biāo)月份的date對象
NSDateComponents *comps = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond|NSCalendarUnitWeekday fromDate:date];
NSLog(@"NSDateComponents是這個樣子的:%@",comps);
// 直接調(diào)用自己weekDay屬性
NSInteger weekday = [comps weekday];
#warning mark --找了很多原因不知道為什么星期數(shù)總是比實(shí)際快一天,有時間找更好的解決方法(暫時用-1天處理了)
weekday--;
NSLog(@"[comps weekday] = %ld",(long)weekday);
if (weekday == 7) {
return 0;
}else return weekday;
}
5. 當(dāng)前時間與之前時間的間隔:
/**
*? @author jaki, 15-09-21 17:09:42
*? @brief? 獲取一個標(biāo)準(zhǔn)時間戳與當(dāng)前時間的時間差
*? @param tinterval 時間戳
*? @return 距離當(dāng)前時間的時間間隔
*/
-(NSString *)getStandardTimeInterval:(NSTimeInterval)interval{
//進(jìn)行時間差比較
//當(dāng)前時間與1970時間戳(秒為單位)
NSTimeInterval time = [[NSDate date] timeIntervalSince1970];
// 當(dāng)前時間戳-當(dāng)時時間戳=差值(比如朋友圈動態(tài)發(fā)表時間為10分鐘前(當(dāng)前時間-發(fā)表時間))
NSTimeInterval timeInterval = time-interval;
//計(jì)算出天、小時、分鐘
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;
}
6.獲取當(dāng)前系統(tǒng)時間:
-(NSString *)getCurrentTime{
NSDateFormatter * formatter = [[NSDateFormatter alloc]init];
// 格式化系統(tǒng)時間字符串
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString * time = [formatter stringFromDate:[NSDate date]];
return time;
}
7.返回年月日時分秒:
#pragma mark --- 對比上邊就比較簡單了不過多啰嗦
-(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;
}
8.date對象NSString互相轉(zhuǎn)換:
// date對象轉(zhuǎn)換成字符串(最后return根據(jù)自己需求處理)
-(NSString * )theTargetDateConversionStr:(NSDate * )date
{
NSDateFormatter* dateFormat = [[NSDateFormatter alloc] init];//實(shí)例化一個NSDateFormatter對象
[dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];//設(shè)定時間格式,這里可以設(shè)置成自己需要的格式
NSString *currentDateStr = [dateFormat stringFromDate:date];
// 根據(jù)自己需求處理字符串
return [currentDateStr substringToIndex:7];
}
// NSString對象轉(zhuǎn)date
-(NSDate* )theTargetStringConversionDate:(NSString *)str
{
//設(shè)置轉(zhuǎn)換格式
NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate *date=[formatter dateFromString:str];
return date;
}
8個方法差不多能夠?qū)崿F(xiàn)一個簡單點(diǎn)的日歷控件了,88大發(fā),大功告成。2017第一篇,比較偏基礎(chǔ)適合我這種菜鳥或者新手,大神路過的話就當(dāng)娛樂一下了。有錯誤的話希望多多指點(diǎn)樓主一下
下面貼一下代碼以及實(shí)現(xiàn)思路:
思路:
剛知道要寫日歷的時候是懵逼的,對NSdate還好、NSCalendar完全沒有概念。查了挺多資料,也在github找了好幾個demo想直接拿過來用,不過不太合適所以決定自己寫。試了tableView、跟colelctionView,最后選擇collectionView需求是展示當(dāng)前月跟之后三個月的日歷。
所以就:
區(qū)頭實(shí)現(xiàn)星期View->四個分區(qū)->區(qū)頭區(qū)尾配合實(shí)現(xiàn)效果,上邊聊得幾個方法處理DataSource.
日歷中標(biāo)記今天的思路是:
實(shí)例變量selectedIndex(今天的下標(biāo)): ---實(shí)現(xiàn)->(獲取到今天幾號,加上今天周幾-1就是日歷中今天那個cell所在的位置了)
直接截圖代碼:
都比較基礎(chǔ)(自己保存下筆記,也分享給能用到的童鞋)
UICollectionView實(shí)現(xiàn):

collectionView.png
DataSource:每個分區(qū)返回item數(shù)量

dataSource返回item個數(shù).png
DataSource: 繪制item

dateSource繪制Cell.png
DataSource:headerView和footerView以及點(diǎn)擊回傳數(shù)據(jù):

區(qū)頭、區(qū)尾、點(diǎn)擊.png
demo地址:https://github.com/rundonkey/DzNSCalendar.git
作者:cocoaAhda
鏈接:http://m.itdecent.cn/p/41ab0eaa78ef
來源:簡書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。
說一點(diǎn)題外話,提交appstore的時候,如果你的歷法類初始化用的是【NSCalendar? * calendar = [NSCalendar currentCalendar],好像蘋果會給你駁回,表示你需要添加一個獲取日歷權(quán)限的key。
而且我在MJRefresh里也看到了一段相同意思的注釋。所以要么去乖乖的加權(quán)限,要么換對應(yīng)identifier的初始化方法吧。
