iOS 仿Keep,動態(tài)獲取當(dāng)前日期,根據(jù)日期選擇界面,日期以周為單位顯示

? ? ?作為一名健身愛好者,使用Keep也有三千分鐘了,最近對他們的根據(jù)日期顯示View界面很感興趣,忍不住動手仿寫了一個。示例圖:

首先來分析一下,它的日期包含三個部分,上個月的最后幾天,當(dāng)前月數(shù)的天數(shù),下個月的頭幾天。如圖:

1.上個月的最后幾天


2.下個月的頭幾天


3.中間的當(dāng)前月的天數(shù),這個不需要展示了,gif圖里面的中間顯示就是

我將界面整體分為上下兩個部分,我們一個一個來分析,我會用盡可能詳細(xì)的方法來描訴,而且我的Demo里有非常詳細(xì)的注釋。

上面的滾動條負(fù)責(zé)顯示日期,而日期的顯示通過button來實(shí)現(xiàn)。滾動條用scrollView來生成,其顯示方式為:一次顯示七個button,分別代表周末-周六,每個button都代表一個日期為幾月幾號。日期的顯示為:周幾-日期。如:星期五,七月一號則顯示為五-1。而如果button的日期為今天則顯示為:今天。

此時出現(xiàn)兩種情況,第一:若前月的第一天不是周末,就需要通過獲取上個月的天數(shù),然后計算所需要的最后幾天為幾月幾號星期幾。第二:若當(dāng)前月的最后一天不是周六,則需要顯示下個月的頭幾天為幾月幾號星期幾。

不過對于這兩個問題的解決,我們只需要獲取上個月的天數(shù)即可,詳情后面解釋。

同時,對于滾動條上的button而言,每一個button都代表一天,我們要通過button的點(diǎn)擊切換下面的頁面。所以,為了讓按鈕更好地保存日期與周幾的信息,且不會與用來識別button的tag屬性混淆,我用了一個自定義的button,只添加了兩個屬性:

//代表按鈕是幾月幾號

@property(nonatomic,assign)NSInteger weekday;

//代表按鈕是幾號

@property(nonatomic,assign)NSInteger day;

而且為了以后的開發(fā)適應(yīng)范圍更廣,此處顯示日期的滾動條寬度不為屏幕的寬度。

而對于下面的View頁面顯示,則每一個View代表一天,View頁面包含兩種:代表今天的View,不代表今天的View。不代表今天的View上有一個按鈕:回到今天,點(diǎn)擊后可跳轉(zhuǎn)到代表今天的View頁面。而代表今天的View則顯示為此處是今天的頁面。

因此根據(jù)分析,我們首先需要獲取當(dāng)前月有多少天,在計算之前我們先熟悉一下NSCalendar(日歷),我的Demo中,日歷的默認(rèn)算法都是公歷

//獲取算法為公歷的日歷

NSCalendar * calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];

而后通過公歷的日歷,獲取當(dāng)前月有多少天,核心代碼如下:

//給定當(dāng)前日期

NSDate * currentDate = [NSDate date];

//計算當(dāng)前月有多少天

NSRange range = [calendar rangeOfUnit:NSCalendarUnitDay

inUnit: NSCalendarUnitMonth

forDate:currentDate];

//range的長度即當(dāng)前月的天數(shù)

return range.length;


然后,我們?nèi)耘f通過系統(tǒng)提供NSCalendar的算法獲取當(dāng)前頁中所有天數(shù)都是周幾,但在獲取之前我們需要獲取指定格式的日期:年 - 月 - 此月的第幾天,而在獲取到此格式之前,我們還需要先確定一下當(dāng)前的時間為X年X月,詳情可參考以下代碼:

//指定日期的顯示格式為年- 月

NSDateFormatter * formatter = [[NSDateFormatter alloc] init];

NSDate * currentDate = [NSDate date];

[formatter setDateFormat:@"yyyy-MM"];

//獲取 年 - 月

NSString * str = [formatter stringFromDate:currentDate];

//? ? NSLog(@"%@",str);

隨后可通過循環(huán)遍歷當(dāng)前月的天數(shù)來拼接格式:年 - 月 - 第幾天,核心代碼:

//聲明格式為:年 - 月 - 第幾天

[formatter setDateFormat:@"yyyy-MM-dd"];

//用來保存周幾的數(shù)組

NSMutableArray * allDaysArray = [[NSMutableArray alloc] init];

//當(dāng)前月有多少天就循環(huán)多少次

for (NSInteger i = 1; i <= dayCount; i++) {

//獲取時間格式如: 年 - 月 - 1 、 年 - 月 - 2

NSString * sr = [NSString stringWithFormat:@"%@-%ld",str,i];

NSDate *suDate = [formatter dateFromString:sr];

//通過時間自定義方法獲取第幾日為星期幾

[allDaysArray addObject:[self getweekDayWithDate:suDate]];

}

而自定義方法getweekDayWithDate里面所做的事情就很簡單了,通過日歷為公歷的NSCalendar方法來計算傳進(jìn)來的日期是星期幾:

- (id) getweekDayWithDate:(NSDate *) date

{

//指定日歷的算法為公歷

NSCalendar * calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];

//獲取指定日期為周幾

NSDateComponents *comps = [calendar components:NSCalendarUnitWeekday fromDate:date];

// 若不減一 則 1 是周日,2是周一 3是周二 以此類推

// 而減一后 則 0為周日,1為周一,2為周二 以此類推

return @([comps weekday]-1);

}

至此,我們獲取到的數(shù)據(jù)有:當(dāng)前月有多少天,每天都是周幾。

而在設(shè)置滾動條之前我們還應(yīng)該先獲取當(dāng)前月的第一天是周幾,我通過將當(dāng)前月每天都是周幾返回的數(shù)據(jù)用數(shù)組保存,就很輕松的可以獲得第一天為周幾,代碼如下:

//獲取當(dāng)前月都是周幾

NSArray *dayArr = [self getAllDaysWithCalender];

//獲取一號的時候是周幾

NSInteger day =? [dayArr[0] integerValue];

隨后開始設(shè)置顯示日期的button的滾動條了,在設(shè)置時,由于當(dāng)前月第一天不是周日,就需要獲取上個月的最后幾天,因此我們需要先獲取上個月總共有多少天,依舊是取算法為公歷的日歷,隨后通過NSDateComponets計算上個月的月數(shù)是幾月,核心代碼如下:

//獲取當(dāng)前日期

NSDate * mydate = [NSDate date];

//設(shè)置關(guān)于日期的算法為上個月

NSDateComponents *adcomps = [[NSDateComponents alloc]init];

[adcomps setMonth:-1];

//設(shè)置日期格式為MM 月

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];

[dateFormatter setDateFormat:@"MM"];

//通過指定算法獲取上個月,并轉(zhuǎn)換格式

NSDate *yesterMonDate = [calendar dateByAddingComponents:adcomps toDate:mydate options:0 ];

NSString *beforeDate = [dateFormatter stringFromDate:yesterMonDate];

而后通過獲取到NSCalendar提供的算法,獲取這個月中總共有多少天:

//獲取上個月有多少天

NSRange range = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:yesterMonDate];

到此,我們得到了上個月的天數(shù),可以計算需要顯示的button信息都為哪些。

我是通過for循環(huán)來計算的,for循環(huán)條件為int i=0; i<day;i++,day為當(dāng)前月的第一號為周幾,因?yàn)閺闹苋臻_始排,所以周幾就代表前面有幾天,獲取上個月的天數(shù)減去i值即為所需顯示的前幾天的日期為幾號,而且是從周日開始排,我一開始還以為要再去計算得到周日那天幾號,算到這步才醒悟不用算~

for循環(huán)的內(nèi)部核心代碼:

//按鈕的frame會在添加時重新設(shè)置,所以此處設(shè)為0即可

//我為了能看到按鈕的正確生成而保存著

//創(chuàng)建所需

ButtonOfWeek *btn = [[ButtonOfWeek alloc]initWithFrame:CGRectMake(i*50, i*30, 50, 30)];

//設(shè)置背景色為隨機(jī)色

btn.backgroundColor = [UIColor colorWithRed:(arc4random_uniform(256)/256.0) green:(arc4random_uniform(256)/256.0) blue:(arc4random_uniform(256)/256.0) alpha:1];

//獲取上個月的天數(shù)

NSInteger num = [self getNumberOfDaysInYesterMonth];

//獲取顯示的前幾天的日期

NSInteger dayNum = num - i;

//? ? ? ? NSLog(@"%ld",dayNum);

//獲取上個月的月數(shù)跟計算出的幾號拼接成weekday值

//用來識別按鈕代表的是幾月幾號

NSString *dayNumOfStr = [NSString stringWithFormat:@"%ld%02ld",self.offNum,dayNum];

//? ? ? ? NSLog(@"%@",dayNumOfStr);

//? ? ? ? NSLog(@"%@",dayNumOfStr);

//設(shè)置按鈕代表第幾號,如7月23號的23號

btn.day = dayNum;

//設(shè)置按鈕的weekday值,也就是日期號

//如:七月一號為701號,七月十三號713號

btn.weekday = [dayNumOfStr integerValue];

//將按鈕添加到數(shù)組

[buttonArr addObject:btn];

在這里解釋一下,buttonArr用來保存滾動條上所有的button,我們先保存所需要生成的所有button,再通過for循環(huán)遍歷添加并重新布局.

在上個月的button顯示之后即為當(dāng)前月的Button信息,獲取的方法無外乎剛才說的那幾種,直接通過for循環(huán)既可以獲取所需的全部button,核心代碼如下,num值為當(dāng)前月的天數(shù):

for (int i = 0; i < num; i++) ?{

ButtonOfWeek *btn = [[ButtonOfWeek alloc]initWithFrame:CGRectMake(i%7*50, i/7*30,50, 30)];

//設(shè)置背景顏色隨機(jī)

btn.backgroundColor = [UIColor colorWithRed:(arc4random_uniform(256)/256.0) green:(arc4random_uniform(256)/256.0) blue:(arc4random_uniform(256)/256.0) alpha:1];

//設(shè)置日期

NSDate *date = [NSDate date];

//獲取當(dāng)前的月數(shù)

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];

[dateFormatter setDateFormat:@"MM"];

//將獲取到的月數(shù)轉(zhuǎn)成字符串

NSString *str = [dateFormatter stringFromDate:date];

//通過月數(shù)幾號拼接成字符串weekday

//設(shè)置weekday值為701,712這種格式,方便后面判斷

NSString *weekStr = [NSString stringWithFormat:@"%@%02d",str,i+1];

//注意:轉(zhuǎn)換成integerValue后,0716會變成716

NSInteger weekday = [weekStr integerValue];

//設(shè)置weekday值

btn.weekday = weekday;

//設(shè)置按鈕顯示的是幾號

btn.day = i+1;

//? ? ? ? NSLog(@"%ld",tag);

//將按鈕添加到數(shù)組

[buttonArr addObject:btn];

}

獲取了當(dāng)前月所需顯示的button后,就要考慮若當(dāng)前月的月底不為周六,則需要補(bǔ)充幾個代表下月的button信息。

解決思路很簡單:當(dāng)前按鈕如果顯示到周一,就代表要填充6個按鈕為下個月的按鈕,所以通過求余計算要填充幾個按鈕,NSInteger afterNum = 7-buttonArr.count%7;

而如果當(dāng)前月的月底正好為周六,就代表afterNum的值為7,此時不添加Button,核心代碼如下:

NSInteger afterNum = 7-buttonArr.count%7;

//如果要顯示的是七天,就一天也不顯示

if (afterNum != 7) {

for (int i = 0; i<afterNum;i++){

ButtonOfWeek *btn = [[ButtonOfWeek alloc]init];

//設(shè)置要顯示的日期,如1號,2號

btn.day = self.buttonArr.count%7+i;

//背景顏色隨機(jī)

btn.backgroundColor = [UIColor colorWithRed:(arc4random_uniform(256)/256.0) green:(arc4random_uniform(256)/256.0) blue:(arc4random_uniform(256)/256.0) alpha:1];

//到此保存了所有的按鈕

[buttonArr addObject:btn];

}

}

獲取了滾動條上所有的Button就可以進(jìn)行添加了,在書寫添加前,先確定一下按鈕的的信息設(shè)置:tag用來識別按鈕,weekday保存的是Button代表的幾月幾號,day表示button代表的是周幾。而weekday與day的值我們都已經(jīng)獲取并保存,tag值在循環(huán)時添加,所以代碼如下:

//設(shè)置滾動的ScrollView

UIScrollView *scrollV? = [[UIScrollView alloc]initWithFrame:CGRectMake(10, 100, 350, 33)];

//循環(huán)遍歷保存的按鈕,依次取出并設(shè)置

//按鈕的設(shè)置

for (int i = 0; i < buttonArr.count; i++) {

//獲取按鈕重新設(shè)置Frame

ButtonOfWeek *btn = buttonArr[i];

btn.frame = CGRectMake(i*50, 0, 50, 30);

//按鈕上的星期幾就是i的值,0為周日,1為周一,依次排列

//將周幾從0、1、2格式轉(zhuǎn)成日、一、二格式

NSString *weekday = self.weekArr[i%7];

//設(shè)置按鈕的顯示文字

//如果按鈕代表的日期是今天,就顯示幾年

//否則就顯示:“日-日期”,如7月6日星期三為:“三-6”,7月3日星期日為:“日-3”

//先獲取今天是幾月幾號

NSInteger today = [self getNumberOfToday];

//根據(jù)按鈕保存的幾月幾號與今天日期進(jìn)行判斷

if (today == btn.weekday) {

[btn setTitle:[NSString stringWithFormat:@"今日"] forState:UIControlStateNormal];

//保存代表今日的按鈕

self.todayButton = btn;

}else{

[btn setTitle:[NSString stringWithFormat:@"%@-%ld",weekday,btn.day] forState:UIControlStateNormal];

}

//? ? ? ? NSLog(@"%ld",btn.weekday);

//將按鈕添加到ScrollView并延長ScrollV的滾動范圍

[scrollV addSubview:btn];

//用tag保存當(dāng)前是第幾個按鈕

btn.tag = i;

//添加點(diǎn)擊事件

[btn addTarget:self action:@selector(clickButtoOfDay:) forControlEvents:UIControlEventTouchUpInside];

//設(shè)置偏移量

scrollV.contentSize = CGSizeMake(scrollV.contentSize.width+btn.frame.size.width, 0);

}

而后開啟scrollView的滾動分頁效果(pagingEnabled),并用全局屬性保存含有顯示button的ScrollView,而后添加ScrollView到當(dāng)前View

在按鈕的下方有一個紅色標(biāo)志,紅色的標(biāo)志條為一個View,隨著按鈕的點(diǎn)擊而改變自身frame,而初始化時frame就位于按鈕的下方,高度為2。

上半部分的按鈕顯示設(shè)置完畢后,就可以動手設(shè)置下半部分的View顯示界面,關(guān)于分頁效果、frame、滾動值這些我就不多說了,詳情看下Demo即可,很簡單的。

關(guān)于顯示View的分析為:View的寬度是屏幕的寬度,有多少個button就設(shè)置多少個View,背景顏色隨機(jī),代表是不同的View。顯示結(jié)果有兩種:代表今日的VIew顯示一個Label信息,不是今日的View顯示一個Button,若需要可修改button的透明度alpha(我觀察后覺得keep里就修改了)。

View顯示內(nèi)容是否是今日的判斷,通過已保存的代表今日的按鈕(代碼中有寫)的tag值與循環(huán)時的i值來比較判斷。

核心代碼如下:

//給ScrollView的每一頁添加一個顯示View

for (int i = 0;i < self.buttonArr.count; i++) {

//設(shè)置顯示View

UIView *baskV = [[UIView alloc]initWithFrame:CGRectMake(i*W, 0, bottomScrollV.frame.size.width, bottomScrollV.frame.size.height)];

//設(shè)置View的顏色為隨機(jī)顏色

baskV.backgroundColor = [UIColor colorWithRed:(arc4random_uniform(256)/256.0) green:arc4random_uniform(256)/256.0 blue:arc4random_uniform(256)/256.0 alpha:1];

//通過代表今日的按鈕的tag值與i比較,得到當(dāng)前View代表的是今日界面

if (i == self.todayButton.tag) {

UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(100, 100, 150, 100)];

label.text = @"這里是今日界面!";

[baskV addSubview:label];

}else{

//給每個View添加一個按鈕為回到今天

UIButton *backToday = [[UIButton alloc]initWithFrame:CGRectMake(100, 100, 100, 44)];

[backToday setTitle:@"回到今日" forState:UIControlStateNormal];

//回到今日的按鈕點(diǎn)擊事件

[backToday addTarget:self action:@selector(clickBackToday:) forControlEvents:UIControlEventTouchUpInside];

backToday.backgroundColor = [UIColor greenColor];

backToday.alpha = 0.3;

[baskV addSubview:backToday];

}

//將View添加到ScrollV上

[bottomScrollV addSubview:baskV];

}


接下來,是對顯示日期的button的點(diǎn)擊事件與View中button的點(diǎn)擊事件實(shí)現(xiàn)。

View中的Button點(diǎn)擊事件很簡單:

#pragma mark - 點(diǎn)擊返回今日的按鈕

-(void)clickBackToday:(UIButton *)sender{

//滾動上面的ScrollView

//滾動范圍X為一頁的寬度 * 滾動的頁數(shù)

[self.topScrollV setContentOffset:CGPointMake(self.todayButton.tag/7*(7*self.todayButton.frame.size.width), 0) animated:YES];

//滾動下面的ScrollView

[self clickButtoOfDay:self.todayButton];

}

?顯示日期的Button的點(diǎn)擊事件

//因?yàn)槠屏繜o論如何都要計算

//所以我選擇ScrollView方式,不過也可以用CollectionView來寫

-(void)clickButtoOfDay:(ButtonOfWeek *)sender{

//改變標(biāo)志View的frame

CGSize lineSize = self.lineView.frame.size;

self.lineView.frame = CGRectMake(sender.tag*sender.frame.size.width, self.lineView.frame.origin.y, lineSize.width, lineSize.height);

//滾動底部的ScrollView

[self.bottomScrollV setContentOffset:CGPointMake(sender.tag*W, 0) animated:YES];

}


Demo地址:https://github.com/DrunkenMouse/copyKeepOfDate

最后說幾點(diǎn):

按鈕的狀態(tài)包括普通、高亮、選中、禁選(enable與userInteractionEnabled,前者會進(jìn)入disabled狀態(tài)后者不會)

而我觀看keep頁面上的按鈕狀態(tài)則分為以下幾種:

禁選時修改alpha值改變透明度,并修改字體顏色,或通過enable的disabled狀態(tài)

休息日時字體顏色為黑色,背景顏色為白色

非休息日時字體顏色為黑色,背景顏色為灰色并切圓,或直接設(shè)置一張圓形圖片(若切圓,建議開啟保存緩存方法)

訓(xùn)練結(jié)束時按鈕添加一個小圖標(biāo),小圖標(biāo)可通過選中與否切換圖片顯示,或按鈕上加一個imageView\Button來顯示圖標(biāo),然后hidden來決定顯示與否

如果是代表當(dāng)前日期的按鈕,則修改字體顏色為綠色

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 1.badgeVaule氣泡提示 2.git終端命令方法> pwd查看全部 >cd>ls >之后桌面找到文件夾內(nèi)容...
    i得深刻方得S閱讀 4,757評論 1 9
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,537評論 0 17
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,251評論 4 61
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,462評論 25 708
  • 前言 動畫主要的目的是讓UI的變動變?nèi)岷停鰪?qiáng)用戶體驗(yàn)。 優(yōu)秀的動畫讓用戶感覺不到頁面的跳轉(zhuǎn)、感覺一切操作很自然。...
    NSNil閱讀 296評論 0 0