iOS自訂日曆控制項的簡單實現過程_IOS

來源:互聯網
上載者:User

因為程式要求要插入一個日曆控制項,該空間的要求是從當天開始及以後的六個月內的日曆,上網查資料基本上都說只要擷取兩個條件(當月第一天周幾和本月一共有多少天)就可以實現一個簡單的日曆,剩下的靠自己的簡單邏輯就OK了,下面開始自己從開始到完成的整個過程

1.首先做NSDate類目,擴充一些方法讓日期之間轉換更加方便

#import <Foundation/Foundation.h>@interface NSDate (LYWCalendar)#pragma mark - 擷取日- (NSInteger)day:(NSDate *)date;#pragma mark - 擷取月- (NSInteger)month:(NSDate *)date;#pragma mark - 擷取年- (NSInteger)year:(NSDate *)date;#pragma mark - 擷取當月第一天周幾- (NSInteger)firstWeekdayInThisMonth:(NSDate *)date;#pragma mark - 擷取當前月有多少天- (NSInteger)totaldaysInMonth:(NSDate *)date;@end

下面一一實現這些方法

#import "NSDate+LYWCalendar.h"@implementation NSDate (LYWCalendar)/** *實現部分 */#pragma mark -- 擷取日- (NSInteger)day:(NSDate *)date{ NSDateComponents *components = [[NSCalendar currentCalendar] components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:date]; return components.day;}#pragma mark -- 擷取月- (NSInteger)month:(NSDate *)date{ NSDateComponents *components = [[NSCalendar currentCalendar] components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:date]; return components.month;}#pragma mark -- 擷取年- (NSInteger)year:(NSDate *)date{ NSDateComponents *components = [[NSCalendar currentCalendar] components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:date]; return components.year;}#pragma mark -- 獲得當前月份第一天星期幾- (NSInteger)firstWeekdayInThisMonth:(NSDate *)date{ NSCalendar *calendar = [NSCalendar currentCalendar]; //設定每周的第一天從周幾開始,預設為1,從周日開始 [calendar setFirstWeekday:1];//1.Sun. 2.Mon. 3.Thes. 4.Wed. 5.Thur. 6.Fri. 7.Sat. 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;}#pragma mark -- 擷取當前月共有多少天- (NSInteger)totaldaysInMonth:(NSDate *)date{ NSRange daysInLastMonth = [[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:date]; return daysInLastMonth.length;}

接下來就要寫邏輯部分了,在ViewController裡面實現,先說思想,首先想到的是用collectionView,但是每個月天數不一樣在日曆中的顯示就不一樣,有時候有五行有時候有六行,既然要用自動填滿就必須考慮到這一點,下面是代碼實現

#import "ViewController.h"#import "Macro.h"#import "NSDate+LYWCalendar.h"#import "LYWCollectionViewCell.h"#import "LYWCollectionReusableView.h"

定義一些全域變數

static NSString *cellID = @"cellID";static NSString *headerID = @"headerID";static NSString *footerID = @"footerID";@implementation ViewController{ //自動布局 UICollectionViewFlowLayout *_layout; //表格視圖 UICollectionView *_collectionView; //當月第一天星期幾 NSInteger firstDayInMounthInWeekly; NSMutableArray *_firstMounth; //容納六個數組的數組 NSMutableArray *_sixArray; }
//定義星期視圖,若為周末則字型顏色為綠色 self.automaticallyAdjustsScrollViewInsets = NO;//關閉自動適應 NSArray *weekTitleArray = @[@"周日",@"周一",@"周二",@"周三",@"周四",@"周五",@"周六"]; for (int i = 0; i < weekTitleArray.count; i++) { UILabel *weekTitleLable = [[UILabel alloc]initWithFrame:CGRectMake(i * ((ScreenWidth/(weekTitleArray.count))), 64, ScreenWidth/(weekTitleArray.count ), 30)]; if (i == 0 || i == 6) {  weekTitleLable.textColor = [UIColor greenColor]; }else{  weekTitleLable.textColor = [UIColor blackColor]; } weekTitleLable.text = [weekTitleArray objectAtIndex:i]; weekTitleLable.textAlignment = NSTextAlignmentCenter; [self.view addSubview:weekTitleLable];}
//設定collectionView及自動布局,代理方法尤為重要 _layout = [[UICollectionViewFlowLayout alloc]init]; //頭部始終在頂端 _layout.sectionHeadersPinToVisibleBounds = YES; //頭部視圖高度 _layout.headerReferenceSize = CGSizeMake(414, 40); _layout.minimumLineSpacing = 0; _layout.minimumInteritemSpacing = 0; _collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 64 + 30, ScreenWidth, ScreenHeight - 64 - 30) collectionViewLayout:_layout]; _collectionView.backgroundColor = [UIColor whiteColor]; //註冊表格 [_collectionView registerClass:[LYWCollectionViewCell class] forCellWithReuseIdentifier:cellID]; //註冊頭視圖 [_collectionView registerClass:[LYWCollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:headerID]; //註冊尾視圖// [_collectionView registerClass:[UICollectionReusableView class] forCellWithReuseIdentifier:footerID];   _collectionView.delegate = self; _collectionView.dataSource = self; [self.view addSubview:_collectionView];

邏輯部分,這裡有個比較長的三項運算式

(daysInMounth > 29 && (firstDayInThisMounth == 6 || firstDayInThisMounth ==5) ? 42 : 35)

就是日曆到底是六行還是七行,這就要根據日曆的特性來判斷了,如果當月天數大於29天並且當月第一天星期六(以這個程式的準則)或者星期天是返回六行剩下的返回三行,也有可能返回四行的,但是就這個程式來說是不可能的也就不需要做判斷了

 //NumberMounthes 為宏定義,表示要顯示月的個數,程式要求是六個月,所以宏定義為六  //#define NumberMounthes 6 //想要展示的月數//建立六個數組,並將這六個數組裝入大數組中 _sixArray = [[NSMutableArray alloc]init]; for (int i = 0; i < NumberMounthes ; i++ ) { NSMutableArray *array = [[NSMutableArray alloc]init]; [_sixArray addObject:array]; } //為六個數組寫入每個月的行事曆資訊 for (int i = 0 ; i < NumberMounthes; i++) { //擷取月份 int mounth = ((int)[currentDate month:currentDate] + i)%12; NSDateComponents *components = [[NSDateComponents alloc]init]; //擷取下個月的年月日資訊,並將其轉為date components.month = mounth; components.year = 2016 + mounth/12; components.day = 1; NSCalendar *calendar = [NSCalendar currentCalendar]; NSDate *nextDate = [calendar dateFromComponents:components]; //擷取該月第一天星期幾 NSInteger firstDayInThisMounth = [nextDate firstWeekdayInThisMonth:nextDate]; //該月的有多少天daysInThisMounth NSInteger daysInThisMounth = [nextDate totaldaysInMonth:nextDate]; NSString *string = [[NSString alloc]init]; for (int j = 0; j < (daysInMounth > 29 && (firstDayInThisMounth == 6 || firstDayInThisMounth ==5) ? 42 : 35) ; j++) {  if (j < firstDayInThisMounth || j > daysInThisMounth + firstDayInThisMounth - 1) {  string = @"";  [[_sixArray objectAtIndex:i]addObject:string];  }else{  string = [NSString stringWithFormat:@"%ld",j - firstDayInThisMounth + 1];  [[_sixArray objectAtIndex:i]addObject:string];  } } }

下面是代理方法

//這兩個不用說,返回cell個數及section個數- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ return [[_sixArray objectAtIndex:section] count];}- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{ return _sixArray.count;}
//這裡是自訂cell,非常簡單的自訂- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ LYWCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath]; UIView *blackgroundView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, cell.frame.size.width, cell.frame.size.height)]; blackgroundView.backgroundColor = [UIColor yellowColor]; cell.dateLable.text = [[_sixArray objectAtIndex:indexPath.section]objectAtIndex:indexPath.row]; NSDate *date = [[NSDate alloc]init]; NSInteger day = [date day:date];  //設定單擊後的顏色   cell.selectedBackgroundView = blackgroundView; return cell;}

自訂cell  .h

#import <UIKit/UIKit.h>@interface LYWCollectionViewCell : UICollectionViewCell@property (nonatomic,strong) UILabel *dateLable;- (instancetype)initWithFrame:(CGRect)frame;@end

.m

#import "LYWCollectionViewCell.h"@implementation LYWCollectionViewCell- (instancetype)initWithFrame:(CGRect)frame{ if (self == [super initWithFrame:frame]) { _dateLable = [[UILabel alloc] initWithFrame:self.bounds]; [_dateLable setTextAlignment:NSTextAlignmentCenter]; [_dateLable setFont:[UIFont systemFontOfSize:17]]; _dateLable.textColor = [UIColor blackColor]; [self addSubview:_dateLable]; } return self;}@end

接著代理

//cell大小及間距- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{ return CGSizeMake(ScreenWidth/7, ScreenWidth/7);}- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{ return UIEdgeInsetsMake(0, 0, 0, 0);}

既然有日曆,總得顯示哪年哪月吧,前面已經註冊表頭視圖了,這裡只需要實現以下代理方法即可

collectionView有點不同其頭視圖也有單獨的類,和cell一樣先自訂headCell,也是非常簡單的自訂

.h檔案

#import <UIKit/UIKit.h>@interface LYWCollectionReusableView : UICollectionReusableView@property (nonatomic,strong) UILabel *dateLable;- (instancetype)initWithFrame:(CGRect)frame;@end

.m檔案

#import "LYWCollectionReusableView.h"@implementation LYWCollectionReusableView- (instancetype)initWithFrame:(CGRect)frame{ if (self == [super initWithFrame:frame]) { _dateLable = [[UILabel alloc] initWithFrame:self.bounds]; [_dateLable setTextAlignment:NSTextAlignmentLeft]; [_dateLable setFont:[UIFont systemFontOfSize:20]]; _dateLable.textColor = [UIColor blackColor]; [self addSubview:_dateLable]; } return self;}@end

接著代理方法,這裡也有個三項判斷式,和上面的大同小異,主要是防止12月顯示為0月

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{ if (kind == UICollectionElementKindSectionHeader) { LYWCollectionReusableView *headerRV = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:headerID forIndexPath:indexPath]; //自訂藍色 headerRV.backgroundColor = DODGER_BLUE; NSDate *currentDate = [[NSDate alloc]init]; NSInteger year = ([currentDate month:currentDate] + indexPath.section)/12 + 2016; NSInteger mounth = ([currentDate month:currentDate] + indexPath.section) % 12 == 0 ? 12 : ([currentDate month:currentDate] + indexPath.section)%12; headerRV.dateLable.text = [NSString stringWithFormat:@"%ld年%ld月",year,mounth]; return headerRV; }else{ return nil; }}

還是代理,處理選中效果,選中的為黃色

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{ LYWCollectionViewCell *cell = [self collectionView:_collectionView cellForItemAtIndexPath:indexPath]; NSDate *currentDate = [[NSDate alloc]init]; //列印當前日期 if (![cell.dateLable.text isEqualToString:@""]) { NSInteger year = ([currentDate month:currentDate] + indexPath.section)/12 + 2016; NSInteger mounth = ([currentDate month:currentDate] + indexPath.section)%12; NSInteger day = [cell.dateLable.text intValue]; NSLog(@"%ld年%02ld月%02ld日",year,mounth,day); } //排除空值cell //擷取月份 NSInteger mounth = ([currentDate month:currentDate] + indexPath.section) % 12 == 0 ? 12 : ([currentDate month:currentDate] + indexPath.section)%12; NSDateComponents *components = [[NSDateComponents alloc]init]; components.month = mounth; components.year = 2016 + mounth/12; components.day = 1; NSCalendar *calendar = [NSCalendar currentCalendar]; NSDate *nextDate = [calendar dateFromComponents:components]; //擷取該月第一天星期幾 NSInteger firstDayInThisMounth = [nextDate firstWeekdayInThisMonth:nextDate]; //該月的有多少天daysInThisMounth NSInteger daysInThisMounth = [nextDate totaldaysInMonth:nextDate]; if ((indexPath.row < firstDayInThisMounth || indexPath.row > daysInThisMounth + firstDayInThisMounth - 1)){ //如果點擊空表格則單擊無效 [collectionView cellForItemAtIndexPath:indexPath].userInteractionEnabled = NO; [collectionView reloadData]; }}

最後展示很爛的效果圖:

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.