From 7f993a72d8e1ab7cb45581ee32d680b15e8d00a3 Mon Sep 17 00:00:00 2001 From: Wenchao Ding Date: Thu, 12 Mar 2015 18:58:37 +0800 Subject: [PATCH] Initial change the container from scrollview to collectionView Initial change the container from scrollview to collectionView, this would make fast scrolling and best performance. --- Example/Pods/Pods.xcodeproj/project.pbxproj | 12 + Pod/Classes/FSCalendar.h | 6 +- Pod/Classes/FSCalendar.m | 394 ++++++-------------- Pod/Classes/FSCalendarCell.h | 25 ++ Pod/Classes/FSCalendarCell.m | 214 +++++++++++ Pod/Classes/FSCalendarPage.m | 2 +- Pod/Classes/FSCalendarUnit.m | 2 - Pod/Classes/NSCalendar+FSExtension.h | 15 + Pod/Classes/NSCalendar+FSExtension.m | 23 ++ Pod/Classes/NSDate+FSExtension.h | 5 +- Pod/Classes/NSDate+FSExtension.m | 39 +- 11 files changed, 450 insertions(+), 287 deletions(-) create mode 100644 Pod/Classes/FSCalendarCell.h create mode 100644 Pod/Classes/FSCalendarCell.m create mode 100644 Pod/Classes/NSCalendar+FSExtension.h create mode 100644 Pod/Classes/NSCalendar+FSExtension.m diff --git a/Example/Pods/Pods.xcodeproj/project.pbxproj b/Example/Pods/Pods.xcodeproj/project.pbxproj index b46a31a..c586885 100644 --- a/Example/Pods/Pods.xcodeproj/project.pbxproj +++ b/Example/Pods/Pods.xcodeproj/project.pbxproj @@ -28,6 +28,8 @@ 4FD6E939AE65BB0AE03EB217 /* SSHolidayUS.h in Headers */ = {isa = PBXBuildFile; fileRef = 1754C9EE0857D9A893A33EFC /* SSHolidayUS.h */; }; 5029DA571AA8111F00712B83 /* UIScrollView+FSExtension.h in Headers */ = {isa = PBXBuildFile; fileRef = 5029DA551AA8111F00712B83 /* UIScrollView+FSExtension.h */; }; 5029DA581AA8111F00712B83 /* UIScrollView+FSExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 5029DA561AA8111F00712B83 /* UIScrollView+FSExtension.m */; }; + 50F20D2F1AB134C40030FC95 /* FSCalendarCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 50F20D2E1AB134C40030FC95 /* FSCalendarCell.m */; }; + 50F20D321AB13D250030FC95 /* NSCalendar+FSExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 50F20D311AB13D250030FC95 /* NSCalendar+FSExtension.m */; }; 54B9A49CD681332E0AC96ACB /* SSHolidayManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 994C4E5A9ADBA9E195ED3178 /* SSHolidayManager.m */; }; 5BCDC7864F306CA125751EF5 /* FSCalendar.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CF2B5A08202EC5C784DA2EE /* FSCalendar.h */; }; 60934D965DDDD69787765519 /* SSHolidayUK.m in Sources */ = {isa = PBXBuildFile; fileRef = 12DE6656C02C82877B52AE19 /* SSHolidayUK.m */; }; @@ -126,6 +128,10 @@ 5029DA551AA8111F00712B83 /* UIScrollView+FSExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIScrollView+FSExtension.h"; path = "Pod/Classes/UIScrollView+FSExtension.h"; sourceTree = ""; }; 5029DA561AA8111F00712B83 /* UIScrollView+FSExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIScrollView+FSExtension.m"; path = "Pod/Classes/UIScrollView+FSExtension.m"; sourceTree = ""; }; 507253B2398C97027677F2D4 /* Pods-FSCalendar-SSLunarDate-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-FSCalendar-SSLunarDate-prefix.pch"; sourceTree = ""; }; + 50F20D2D1AB134C40030FC95 /* FSCalendarCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FSCalendarCell.h; path = Pod/Classes/FSCalendarCell.h; sourceTree = ""; }; + 50F20D2E1AB134C40030FC95 /* FSCalendarCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FSCalendarCell.m; path = Pod/Classes/FSCalendarCell.m; sourceTree = ""; }; + 50F20D301AB13D250030FC95 /* NSCalendar+FSExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSCalendar+FSExtension.h"; path = "Pod/Classes/NSCalendar+FSExtension.h"; sourceTree = ""; }; + 50F20D311AB13D250030FC95 /* NSCalendar+FSExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSCalendar+FSExtension.m"; path = "Pod/Classes/NSCalendar+FSExtension.m"; sourceTree = ""; }; 54F8D017A120281736F206D6 /* UIView+FSExtension.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIView+FSExtension.h"; path = "Pod/Classes/UIView+FSExtension.h"; sourceTree = ""; }; 592634D55D346607A4B7530F /* FSCalendarPage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FSCalendarPage.m; path = Pod/Classes/FSCalendarPage.m; sourceTree = ""; }; 64B1A1249E2764AC2282EB7B /* Pods-Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Tests.release.xcconfig"; sourceTree = ""; }; @@ -269,12 +275,16 @@ 6C018919F1D7CA414C325BFC /* FSCalendarHeader.m */, 449CB7D957C393F01139A125 /* FSCalendarPage.h */, 592634D55D346607A4B7530F /* FSCalendarPage.m */, + 50F20D2D1AB134C40030FC95 /* FSCalendarCell.h */, + 50F20D2E1AB134C40030FC95 /* FSCalendarCell.m */, 2EDF73DE3D0B3F200CAAD391 /* FSCalendarUnit.h */, 13C407A02107C4EC403F85BA /* FSCalendarUnit.m */, FD7388654A8B1EEC514563FD /* NSDate+FSExtension.h */, 2AF241AFE2CAC20B7AE30AD0 /* NSDate+FSExtension.m */, 54F8D017A120281736F206D6 /* UIView+FSExtension.h */, 8ABD412B8358CA722FC65E56 /* UIView+FSExtension.m */, + 50F20D301AB13D250030FC95 /* NSCalendar+FSExtension.h */, + 50F20D311AB13D250030FC95 /* NSCalendar+FSExtension.m */, 5029DA551AA8111F00712B83 /* UIScrollView+FSExtension.h */, 5029DA561AA8111F00712B83 /* UIScrollView+FSExtension.m */, D2F28E91854D59AA3E5E6865 /* Support Files */, @@ -616,6 +626,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 50F20D2F1AB134C40030FC95 /* FSCalendarCell.m in Sources */, + 50F20D321AB13D250030FC95 /* NSCalendar+FSExtension.m in Sources */, 969FDB3DE912C57F822E2420 /* Pods-FSCalendar-dummy.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Pod/Classes/FSCalendar.h b/Pod/Classes/FSCalendar.h index 6bb0007..60e7799 100644 --- a/Pod/Classes/FSCalendar.h +++ b/Pod/Classes/FSCalendar.h @@ -11,8 +11,8 @@ @class FSCalendar, FSCalendarUnit, FSCalendarHeader; typedef NS_ENUM(NSInteger, FSCalendarFlow) { - FSCalendarFlowHorizontal = 0, - FSCalendarFlowVertical = 1 + FSCalendarFlowHorizontal = UICollectionViewScrollDirectionHorizontal, + FSCalendarFlowVertical = UICollectionViewScrollDirectionVertical }; typedef NS_OPTIONS(NSInteger, FSCalendarUnitAnimation) { @@ -60,8 +60,8 @@ typedef NS_OPTIONS(NSInteger, FSCalendarUnitState) { @property (copy, nonatomic) NSDate *currentDate; @property (copy, nonatomic) NSDate *selectedDate; -@property (copy, nonatomic) NSDate *currentMonth; +@property (readonly, nonatomic) NSDate *currentMonth; @property (assign, nonatomic) FSCalendarFlow flow; @property (assign, nonatomic) BOOL autoAdjustTitleSize; diff --git a/Pod/Classes/FSCalendar.m b/Pod/Classes/FSCalendar.m index 0f542a6..c4dbbc4 100644 --- a/Pod/Classes/FSCalendar.m +++ b/Pod/Classes/FSCalendar.m @@ -13,32 +13,27 @@ #import "FSCalendarHeader.h" #import "UIView+FSExtension.h" #import "NSDate+FSExtension.h" +#import "NSCalendar+FSExtension.h" +#import "FSCalendarCell.h" #define kWeekHeight roundf(self.fs_height/9) #define kBlueText [UIColor colorWithRed:14/255.0 green:69/255.0 blue:221/255.0 alpha:1.0] #define kPink [UIColor colorWithRed:198/255.0 green:51/255.0 blue:42/255.0 alpha:1.0] #define kBlue [UIColor colorWithRed:31/255.0 green:119/255.0 blue:219/255.0 alpha:1.0] -const char * flowKey; +#define kNumberOfPages 61 // From 1970 to 2040 -@interface FSCalendar () +@interface FSCalendar () + +@property (strong, nonatomic) UICollectionView *collectionView; +@property (strong, nonatomic) UICollectionViewFlowLayout *collectionViewFlowLayout; -@property (strong, nonatomic) UIScrollView *scrollView; @property (strong, nonatomic) NSMutableArray *weekdays; -@property (strong, nonatomic) FSCalendarPage *page0; -@property (strong, nonatomic) FSCalendarPage *page1; - -@property (strong, nonatomic) NSMutableDictionary *unitColors; +@property (strong, nonatomic) NSMutableDictionary *backgroundColors; @property (strong, nonatomic) NSMutableDictionary *titleColors; @property (strong, nonatomic) NSMutableDictionary *subtitleColors; -@property (assign, nonatomic) NSInteger currentPage; -@property (assign, nonatomic) CGFloat baseOffset; - -@property (readonly, nonatomic) CGSize flowSize; -@property (readonly, nonatomic) CGPoint flowOffset; -@property (readonly, nonatomic) CGFloat flowSide; -@property (readonly, nonatomic) CGFloat flowScrollOffset; +@property (readonly, nonatomic) NSInteger currentPage; - (BOOL)shouldSelectDate:(NSDate *)date; - (void)didSelectDate:(NSDate *)date; @@ -46,7 +41,8 @@ const char * flowKey; - (NSString *)subtitleForDate:(NSDate *)date; - (void)adjustTitleIfNecessary; -- (void)reloadUnits; + +- (NSDate *)dateForIndexPath:(NSIndexPath *)indexPath; @end @@ -91,42 +87,36 @@ const char * flowKey; [self addSubview:weekdayLabel]; } - _scrollView = [[UIScrollView alloc] initWithFrame:CGRectZero]; - _scrollView.delegate = self; - _scrollView.backgroundColor = [UIColor clearColor]; - _scrollView.bounces = YES; - _scrollView.opaque = NO; - _scrollView.pagingEnabled = YES; - _scrollView.showsHorizontalScrollIndicator = NO; - _scrollView.showsVerticalScrollIndicator = NO; - _scrollView.tag = -1; - _scrollView.delaysContentTouches = NO; - _scrollView.canCancelContentTouches = YES; - [self addSubview:_scrollView]; + _collectionViewFlowLayout = [[UICollectionViewFlowLayout alloc] init]; + _collectionViewFlowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal; + _collectionViewFlowLayout.minimumInteritemSpacing = 0; + _collectionViewFlowLayout.minimumLineSpacing = 0; - _page0 = [[FSCalendarPage alloc] initWithFrame:CGRectZero]; - _page0.tag = 0; - [_scrollView addSubview:_page0]; + _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero + collectionViewLayout:_collectionViewFlowLayout]; + _collectionView.dataSource = self; + _collectionView.delegate = self; + _collectionView.backgroundColor = [UIColor clearColor]; + _collectionView.bounces = YES; + _collectionView.pagingEnabled = YES; + _collectionView.showsHorizontalScrollIndicator = NO; + _collectionView.showsVerticalScrollIndicator = NO; + _collectionView.delaysContentTouches = NO; + _collectionView.canCancelContentTouches = YES; + [_collectionView registerClass:[FSCalendarCell class] forCellWithReuseIdentifier:@"cell"]; + [self addSubview:_collectionView]; - _page1 = [[FSCalendarPage alloc] initWithFrame:CGRectZero]; - _page1.tag = 1; - [_scrollView addSubview:_page1]; + _collectionView.collectionViewLayout = _collectionViewFlowLayout; _currentDate = [NSDate date]; _currentMonth = [_currentDate copy]; - [_page0.subviews setValue:self forKeyPath:@"dataSource"]; - [_page0.subviews setValue:self forKeyPath:@"delegate"]; - [_page1.subviews setValue:self forKeyPath:@"dataSource"]; - [_page1.subviews setValue:self forKeyPath:@"delegate"]; - - - _unitColors = [NSMutableDictionary dictionaryWithCapacity:4]; - _unitColors[@(FSCalendarUnitStateNormal)] = [UIColor clearColor]; - _unitColors[@(FSCalendarUnitStateSelected)] = kBlue; - _unitColors[@(FSCalendarUnitStateDisabled)] = [UIColor clearColor]; - _unitColors[@(FSCalendarUnitStatePlaceholder)] = [UIColor clearColor]; - _unitColors[@(FSCalendarUnitStateToday)] = kPink; + _backgroundColors = [NSMutableDictionary dictionaryWithCapacity:4]; + _backgroundColors[@(FSCalendarUnitStateNormal)] = [UIColor clearColor]; + _backgroundColors[@(FSCalendarUnitStateSelected)] = kBlue; + _backgroundColors[@(FSCalendarUnitStateDisabled)] = [UIColor clearColor]; + _backgroundColors[@(FSCalendarUnitStatePlaceholder)] = [UIColor clearColor]; + _backgroundColors[@(FSCalendarUnitStateToday)] = kPink; _titleColors = [NSMutableDictionary dictionaryWithCapacity:4]; _titleColors[@(FSCalendarUnitStateNormal)] = [UIColor darkTextColor]; @@ -151,89 +141,72 @@ const char * flowKey; - (void)layoutSubviews { [super layoutSubviews]; - - if (_scrollView.tag == -1) { - if (CGRectEqualToRect(_scrollView.frame, CGRectZero)) { - // make sure this is called only at initialing - _scrollView.frame = CGRectMake(0, kWeekHeight, self.fs_width, self.fs_height-kWeekHeight); - _scrollView.contentInset = UIEdgeInsetsZero; - _scrollView.scrollIndicatorInsets = UIEdgeInsetsZero; - - [_weekdays enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - CGFloat width = self.fs_width/_weekdays.count; - CGFloat height = kWeekHeight; - [obj setFrame:CGRectMake(idx*width, 0, width, height)]; - }]; - } - _page0.frame = CGRectMake(0, 0, _scrollView.fs_width, _scrollView.fs_height); - _page1.frame = CGRectOffset(_page0.frame, self.flowOffset.x, self.flowOffset.y); - [self reloadData]; - _scrollView.contentSize = self.flowSize; - _scrollView.tag = 0; - } - [self adjustTitleIfNecessary]; + CGFloat padding = _collectionView.fs_height * 0.01; + _collectionView.frame = CGRectMake(0, kWeekHeight, self.fs_width, self.fs_height-kWeekHeight); + _collectionViewFlowLayout.itemSize = CGSizeMake(_collectionView.fs_width/7, + (_collectionView.fs_height-padding*2)/6); + _collectionViewFlowLayout.sectionInset = UIEdgeInsetsMake(padding, 0, padding, 0); + [_weekdays enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + CGFloat width = self.fs_width/_weekdays.count; + CGFloat height = kWeekHeight; + [obj setFrame:CGRectMake(idx*width, 0, width, height)]; + }]; + [self adjustTitleIfNecessary]; } -- (void)dealloc +- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { - _scrollView.delegate = nil; + return kNumberOfPages; } -#pragma mark - UIScrollView Delegate - -- (void)scrollViewDidScroll:(UIScrollView *)scrollView +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { - CGFloat offset = self.flowScrollOffset; - if (offset > self.flowSide) { - _scrollView.bounds = CGRectOffset(_scrollView.bounds, -self.flowOffset.x, -self.flowOffset.y); - _page1.frame = CGRectOffset(_page1.frame, -self.flowOffset.x, -self.flowOffset.y); - _page0.frame = CGRectOffset(_page1.frame, self.flowOffset.x, self.flowOffset.y); - _baseOffset += self.flowOffset.x + self.flowOffset.y; - offset -= (self.flowOffset.x + self.flowOffset.y); - [self updatePointer]; - [self updatePage:_page1 forIndex:self.currentPage + 1]; - } else if (offset < 0) { - _scrollView.bounds = CGRectOffset(_scrollView.bounds, self.flowOffset.x, self.flowOffset.y); - _page0.frame = CGRectOffset(_page0.frame, self.flowOffset.x, self.flowOffset.y); - _page1.frame = CGRectOffset(_page0.frame, -self.flowOffset.x, -self.flowOffset.y); - _baseOffset -= (self.flowOffset.x + self.flowOffset.y); - offset += (self.flowOffset.x + self.flowOffset.y); - [self updatePointer]; - [self updatePage:_page0 forIndex:self.currentPage - 1]; - } - self.currentPage = (roundf(offset/self.flowSide)*self.flowSide+self.baseOffset)/self.flowSide; - if (_header) { - _header.scrollOffset = (self.baseOffset+offset)/self.flowSide; + return 42; +} + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath +{ + FSCalendarCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath]; + cell.titleColors = self.titleColors; + cell.subtitleColors = self.subtitleColors; + cell.backgroundColors = self.backgroundColors; + cell.month = [[NSCalendar fs_sharedCalendar] dateByAddingUnit:NSMonthCalendarUnit + value:indexPath.section + toDate:[NSDate dateWithTimeIntervalSince1970:1] + options:0]; + cell.date = [self dateForIndexPath:indexPath]; + if (!_autoAdjustTitleSize) { + cell.titleLabel.font = _titleFont; + cell.subtitleLabel.font = _subtitleFont; } + NSLog(@"%@::%@",@(indexPath.row),@(cell.date.fs_day)); + return cell; +} + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath +{ } #pragma mark - Setter & Getter -- (void)setCurrentPage:(NSInteger)currentPage +- (NSInteger)currentPage { - if (_currentPage != currentPage) { - _currentPage = currentPage; - self.currentMonth = [_currentDate fs_dateByAddingMonths:currentPage]; - if (_delegate && [_delegate respondsToSelector:@selector(calendarCurrentMonthDidChange:)]) { - [_delegate calendarCurrentMonthDidChange:self]; - } + if (self.flow == FSCalendarFlowHorizontal) { + return round(_collectionView.contentOffset.x)/_collectionView.fs_width; + } else { + return round(_collectionView.contentOffset.y)/_collectionView.fs_height; } } - (void)setFlow:(FSCalendarFlow)flow { - if (self.flow != flow) { - objc_setAssociatedObject(self, &flowKey, @(flow), OBJC_ASSOCIATION_COPY_NONATOMIC); - _scrollView.tag = -1; - _baseOffset = _currentPage * self.flowSide; - [self setNeedsLayout]; - } + _collectionViewFlowLayout.scrollDirection = (UICollectionViewScrollDirection)flow; } - (FSCalendarFlow)flow { - return [objc_getAssociatedObject(self, &flowKey) integerValue]; + return (FSCalendarFlow)_collectionViewFlowLayout.scrollDirection; } - (void)setWeekdayFont:(UIFont *)weekdayFont @@ -264,8 +237,7 @@ const char * flowKey; if (![_currentDate isEqualToDate:currentDate]) { _currentDate = [currentDate copy]; _currentMonth = [_currentDate copy]; - [self updatePage:_page0 forIndex:0]; - [self updatePage:_page1 forIndex:1]; + if (_header) { _header.calendar = nil; _header.calendar = self; @@ -298,7 +270,7 @@ const char * flowKey; } else { [_titleColors removeObjectForKey:@(FSCalendarUnitStateNormal)]; } - [self reloadUnits]; + [self reloadData]; } - (void)setTitleSelectionColor:(UIColor *)color @@ -308,7 +280,7 @@ const char * flowKey; } else { [_titleColors removeObjectForKey:@(FSCalendarUnitStateSelected)]; } - [self reloadUnits]; + [self reloadData]; } - (void)setTitleTodayColor:(UIColor *)color @@ -318,7 +290,7 @@ const char * flowKey; } else { [_titleColors removeObjectForKey:@(FSCalendarUnitStateToday)]; } - [self reloadUnits]; + [self reloadData]; } - (void)setTitlePlaceholderColor:(UIColor *)color @@ -328,7 +300,7 @@ const char * flowKey; } else { [_titleColors removeObjectForKey:@(FSCalendarUnitStatePlaceholder)]; } - [self reloadUnits]; + [self reloadData]; } - (void)setTitleWeekendColor:(UIColor *)color @@ -338,7 +310,7 @@ const char * flowKey; } else { [_titleColors removeObjectForKey:@(FSCalendarUnitStateWeekend)]; } - [self reloadUnits]; + [self reloadData]; } - (void)setSubtitleDefaultColor:(UIColor *)color @@ -348,7 +320,7 @@ const char * flowKey; } else { [_subtitleColors removeObjectForKey:@(FSCalendarUnitStateNormal)]; } - [self reloadUnits]; + [self reloadData]; } - (void)setSubtitleSelectionColor:(UIColor *)color @@ -358,7 +330,7 @@ const char * flowKey; } else { [_subtitleColors removeObjectForKey:@(FSCalendarUnitStateSelected)]; } - [self reloadUnits]; + [self reloadData]; } - (void)setSubtitleTodayColor:(UIColor *)color @@ -368,7 +340,7 @@ const char * flowKey; } else { [_subtitleColors removeObjectForKey:@(FSCalendarUnitStateToday)]; } - [self reloadUnits]; + [self reloadData]; } - (void)setSubtitlePlaceholderColor:(UIColor *)color @@ -378,7 +350,7 @@ const char * flowKey; } else { [_subtitleColors removeObjectForKey:@(FSCalendarUnitStatePlaceholder)]; } - [self reloadUnits]; + [self reloadData]; } - (void)setSubtitleWeekendColor:(UIColor *)color @@ -388,37 +360,32 @@ const char * flowKey; } else { [_subtitleColors removeObjectForKey:@(FSCalendarUnitStateWeekend)]; } - [self reloadUnits]; + [self reloadData]; } - (void)setSelectionColor:(UIColor *)color { if (color) { - _unitColors[@(FSCalendarUnitStateSelected)] = color; + _backgroundColors[@(FSCalendarUnitStateSelected)] = color; } else { - [_unitColors removeObjectForKey:@(FSCalendarUnitStateSelected)]; + [_backgroundColors removeObjectForKey:@(FSCalendarUnitStateSelected)]; } - [self reloadUnits]; + [self reloadData]; } - (void)setTodayColor:(UIColor *)color { if (color) { - _unitColors[@(FSCalendarUnitStateToday)] = color; + _backgroundColors[@(FSCalendarUnitStateToday)] = color; } else { - [_unitColors removeObjectForKey:@(FSCalendarUnitStateToday)]; + [_backgroundColors removeObjectForKey:@(FSCalendarUnitStateToday)]; } - [self reloadUnits]; + [self reloadData]; } - (void)setEventColor:(UIColor *)color { - [_page0.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - [(FSCalendarUnit *)obj setEventColor:color]; - }]; - [_page1.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - [(FSCalendarUnit *)obj setEventColor:color]; - }]; + } - (void)setTitleFont:(UIFont *)font @@ -428,8 +395,6 @@ const char * flowKey; if (_autoAdjustTitleSize) { return; } - [_page0.subviews setValue:_titleFont forKeyPath:@"titleFont"]; - [_page1.subviews setValue:_titleFont forKeyPath:@"titleFont"]; } } @@ -440,8 +405,6 @@ const char * flowKey; if (_autoAdjustTitleSize) { return; } - [_page0.subviews setValue:_subtitleFont forKeyPath:@"subtitleFont"]; - [_page1.subviews setValue:_subtitleFont forKeyPath:@"subtitleFont"]; } } @@ -453,128 +416,40 @@ const char * flowKey; } } -#pragma mark - Public - -- (void)reloadData -{ - [self updatePage:_page0 forIndex:_currentPage]; - [self updatePage:_page1 forIndex:_currentPage + 1]; -} - #pragma mark - Private +- (NSDate *)dateForIndexPath:(NSIndexPath *)indexPath +{ + NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; + NSDate *currentMonth = [calendar dateByAddingUnit:NSMonthCalendarUnit + value:indexPath.section + toDate:[NSDate dateWithTimeIntervalSince1970:1] + options:0]; + NSDate *firstDayOfMonth = [NSDate fs_dateWithYear:currentMonth.fs_year month:currentMonth.fs_month day:1]; + NSInteger numberOfPlaceholdersForPrev = (firstDayOfMonth.fs_weekday - 1) ? : 7; + NSDate *firstDateOfPage = [firstDayOfMonth fs_dateBySubtractingDays:numberOfPlaceholdersForPrev-1]; + NSDate *dateForRow = [firstDateOfPage fs_dateByAddingDays:7*(indexPath.row%6)+indexPath.row/6]; + return dateForRow; +} + - (void)adjustTitleIfNecessary { UIFont *titleFont = _titleFont; UIFont *subtitleFont = _subtitleFont; UIFont *headerFont = _headerTitleFont; UIFont *weekdayFont = _weekdayFont; - if (_autoAdjustTitleSize) { - titleFont = [titleFont fontWithSize:_scrollView.fs_height/3/6]; - subtitleFont = [subtitleFont fontWithSize:_scrollView.fs_height/4.3/6]; - headerFont = titleFont; - weekdayFont = titleFont; - } - [_page0.subviews setValue:titleFont forKeyPath:@"titleFont"]; - [_page1.subviews setValue:titleFont forKeyPath:@"titleFont"]; - [_page0.subviews setValue:subtitleFont forKeyPath:@"subtitleFont"]; - [_page1.subviews setValue:subtitleFont forKeyPath:@"subtitleFont"]; +// if (_autoAdjustTitleSize) { +// titleFont = [titleFont fontWithSize:_scrollView.fs_height/3/6]; +// subtitleFont = [subtitleFont fontWithSize:_scrollView.fs_height/4.3/6]; +// headerFont = titleFont; +// weekdayFont = titleFont; +// } [_weekdays setValue:weekdayFont forKey:@"font"]; if (_header) { [_header setTitleFont:headerFont]; } } -- (void)reloadUnits -{ - [_page0.subviews makeObjectsPerformSelector:@selector(setNeedsLayout)]; - [_page1.subviews makeObjectsPerformSelector:@selector(setNeedsLayout)]; -} - -- (void)updatePointer -{ - switch (self.flow) { - case FSCalendarFlowHorizontal: - if (_page0.fs_left > _page1.fs_left) { - id temp0 = _page0; - self.page0 = _page1; - self.page1 = temp0; - } - break; - case FSCalendarFlowVertical: - if (_page0.fs_top > _page1.fs_top) { - id temp0 = _page0; - self.page0 = _page1; - self.page1 = temp0; - } - break; - default: - break; - } -} - -- (CGSize)flowSize -{ - switch (self.flow) { - case FSCalendarFlowHorizontal: - return CGSizeMake(_scrollView.fs_width * 2, _scrollView.fs_height); - break; - case FSCalendarFlowVertical: - return CGSizeMake(_scrollView.fs_width, _scrollView.fs_height * 2); - break; - default: - break; - } -} - -- (CGPoint)flowOffset -{ - switch (self.flow) { - case FSCalendarFlowHorizontal: - return CGPointMake(_scrollView.fs_width, 0); - break; - case FSCalendarFlowVertical: - return CGPointMake(0, _scrollView.fs_height); - break; - default: - break; - } -} - -- (CGFloat)flowSide -{ - switch (self.flow) { - case FSCalendarFlowHorizontal: - return _scrollView.fs_width; - break; - case FSCalendarFlowVertical: - return _scrollView.fs_height; - break; - default: - break; - } -} - -- (CGFloat)flowScrollOffset -{ - switch (self.flow) { - case FSCalendarFlowHorizontal: - return _scrollView.contentOffset.x; - break; - case FSCalendarFlowVertical: - return _scrollView.contentOffset.y; - break; - default: - break; - } -} - -- (void)updatePage:(FSCalendarPage *)page forIndex:(NSInteger)index -{ - NSDate *destDate = [_currentDate fs_dateByAddingMonths:index]; - page.date = destDate; -} - - (BOOL)shouldSelectDate:(NSDate *)date { if (_delegate && [_delegate respondsToSelector:@selector(calendar:shouldSelectDate:)]) { @@ -618,8 +493,8 @@ const char * flowKey; { if (_unitStyle != unitStyle) { _unitStyle = unitStyle; - [_page0.subviews setValue:@(unitStyle) forKeyPath:@"style"]; - [_page1.subviews setValue:@(unitStyle) forKeyPath:@"style"]; +// [_page0.subviews setValue:@(unitStyle) forKeyPath:@"style"]; +// [_page1.subviews setValue:@(unitStyle) forKeyPath:@"style"]; } } @@ -664,7 +539,7 @@ const char * flowKey; - (UIColor *)unitColorForUnit:(FSCalendarUnit *)unit { - return _unitColors[@(unit.absoluteState)]; + return _backgroundColors[@(unit.absoluteState)]; } - (UIColor *)titleColorForUnit:(FSCalendarUnit *)unit @@ -677,34 +552,11 @@ const char * flowKey; return _subtitleColors[@(unit.absoluteState)]; } -#pragma mark - Unit Delegate +#pragma mark - Public -- (void)handleUnitTap:(FSCalendarUnit *)unit +- (void)reloadData { - if ([self shouldSelectDate:unit.date] && !unit.isSelected) { - if (unit.isPlaceholder) { - NSArray *subviews; - if ([_page0.subviews containsObject:unit]) { - subviews = _page0.subviews; - } else { - subviews = _page1.subviews; - } - NSInteger index = [subviews indexOfObject:unit]; - CGPoint destOffset; - if (index <= 7) { - destOffset = CGPointMake(_scrollView.contentOffset.x-[self flowOffset].x, _scrollView.contentOffset.y-self.flowOffset.y); - } else { - destOffset = CGPointMake(_scrollView.contentOffset.x+[self flowOffset].x, _scrollView.contentOffset.y+self.flowOffset.y); - } - [_scrollView setContentOffset:destOffset animated:YES]; - } - self.selectedDate = unit.date; - [self didSelectDate:unit.date]; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - [_page0.subviews makeObjectsPerformSelector:@selector(setNeedsLayout)]; - [_page1.subviews makeObjectsPerformSelector:@selector(setNeedsLayout)]; - }); - } + [_collectionView reloadData]; } @end diff --git a/Pod/Classes/FSCalendarCell.h b/Pod/Classes/FSCalendarCell.h new file mode 100644 index 0000000..608d436 --- /dev/null +++ b/Pod/Classes/FSCalendarCell.h @@ -0,0 +1,25 @@ +// +// FSCalendarCell.h +// Pods +// +// Created by Wenchao Ding on 12/3/15. +// +// + +#import + +@interface FSCalendarCell : UICollectionViewCell + +@property (strong, nonatomic) UILabel *titleLabel; +@property (strong, nonatomic) UILabel *subtitleLabel; + +@property (strong, nonatomic) NSDictionary *titleColors; +@property (strong, nonatomic) NSDictionary *subtitleColors; +@property (strong, nonatomic) NSDictionary *backgroundColors; + +@property (copy, nonatomic) NSDate *date; +@property (copy, nonatomic) NSDate *month; + +@property (assign, nonatomic) FSCalendarCellStyle *style; + +@end diff --git a/Pod/Classes/FSCalendarCell.m b/Pod/Classes/FSCalendarCell.m new file mode 100644 index 0000000..063c0fc --- /dev/null +++ b/Pod/Classes/FSCalendarCell.m @@ -0,0 +1,214 @@ +// +// FSCalendarCell.m +// Pods +// +// Created by Wenchao Ding on 12/3/15. +// +// + +#import "FSCalendarCell.h" +#import "FSCalendar.h" +#import "UIView+FSExtension.h" +#import "NSDate+FSExtension.h" + +#define kAnimationDuration 0.15 + +#define kTitleHeight self.contentView.fs_height*5.0/6.0 +#define kDiameter MIN(self.contentView.fs_height*5.0/6.0,self.contentView.fs_width) + +@interface FSCalendarCell () + +@property (readonly, nonatomic) UICollectionView *collectionView; +@property (readonly, nonatomic) FSCalendar *calendar; + +@property (strong, nonatomic) CAShapeLayer *backgroundLayer; +@property (strong, nonatomic) CAShapeLayer *eventLayer; + +@property (nonatomic, readonly, getter = isPlaceholder) BOOL placeholder; +@property (nonatomic, readonly, getter = isToday) BOOL today; +@property (nonatomic, readonly, getter = isWeekend) BOOL weekend; + +- (UIColor *)colorForCurrentStateInDictionary:(NSDictionary *)dictionary; + +- (void)configureCell; + +@end + +@implementation FSCalendarCell + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + _titleLabel.textAlignment = NSTextAlignmentCenter; + _titleLabel.font = [UIFont systemFontOfSize:15]; + _titleLabel.textColor = [UIColor darkTextColor]; + [self.contentView addSubview:_titleLabel]; + + _subtitleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + _subtitleLabel.textAlignment = NSTextAlignmentCenter; + _subtitleLabel.font = [UIFont systemFontOfSize:10]; + _subtitleLabel.textColor = [UIColor lightGrayColor]; + [self.contentView addSubview:_subtitleLabel]; + + _backgroundLayer = [CAShapeLayer layer]; + _backgroundLayer.backgroundColor = [UIColor clearColor].CGColor; + _backgroundLayer.hidden = YES; + _backgroundLayer.anchorPoint = CGPointMake(0.5, 0.5); + [self.contentView.layer insertSublayer:_backgroundLayer below:_titleLabel.layer]; + + _eventLayer = [CAShapeLayer layer]; + _eventLayer.backgroundColor = [UIColor clearColor].CGColor; + _eventLayer.fillColor = [UIColor cyanColor].CGColor; + _eventLayer.path = [UIBezierPath bezierPathWithOvalInRect:_eventLayer.bounds].CGPath; + [self.contentView.layer addSublayer:_eventLayer]; + } + return self; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + _backgroundLayer.frame = CGRectMake((self.contentView.fs_width-kDiameter)/2, + (kTitleHeight-kDiameter)/2, + kDiameter, + kDiameter); + + CGFloat eventSize = _backgroundLayer.frame.size.height/6.0; + _eventLayer.frame = CGRectMake((_backgroundLayer.frame.size.width-eventSize)/2+_backgroundLayer.frame.origin.x, CGRectGetMaxY(_backgroundLayer.frame)+eventSize*0.2, eventSize*0.8, eventSize*0.8); + _eventLayer.path = [UIBezierPath bezierPathWithOvalInRect:_eventLayer.bounds].CGPath; +} + +#pragma mark - Setters + +- (void)setSelected:(BOOL)selected +{ + [super setSelected:selected]; + if (!_backgroundLayer.hidden) { + _backgroundLayer.hidden = YES; + } + if (selected) { + [self showAnimation]; + } + [self configureCell]; +} + +- (void)setDate:(NSDate *)date +{ + if (![_date isEqualToDate:date]) { + _date = date; + } + [self configureCell]; +} + + + +#pragma mark - Private + +- (UICollectionView *)collectionView +{ + UIView *superview = self.superview; + while (superview && ![superview isKindOfClass:[UICollectionView class]]) { + superview = superview.superview; + } + return (UICollectionView *)superview; +} + +- (FSCalendar *)calendar +{ + return (FSCalendar *)self.collectionView.superview; +} + +- (void)configureCell +{ + _titleLabel.text = [NSString stringWithFormat:@"%@",@(_date.fs_day)]; + if (self.calendar.dataSource && [self.calendar.dataSource respondsToSelector:@selector(calendar:subtitleForDate:)]) { + _subtitleLabel.text = [self.calendar.dataSource calendar:self.calendar subtitleForDate:_date]; + } else { + _subtitleLabel.text = nil; + } + _titleLabel.textColor = [self colorForCurrentStateInDictionary:_titleColors]; + _subtitleLabel.textColor = [self colorForCurrentStateInDictionary:_subtitleColors]; + _backgroundLayer.fillColor = [self colorForCurrentStateInDictionary:_backgroundColors].CGColor; + + CGFloat titleHeight = [_titleLabel.text sizeWithAttributes:@{NSFontAttributeName:self.titleLabel.font}].height; + if (_subtitleLabel.text) { + _subtitleLabel.hidden = NO; + CGFloat subtitleHeight = [_subtitleLabel.text sizeWithAttributes:@{NSFontAttributeName:self.subtitleLabel.font}].height; + CGFloat height = titleHeight + subtitleHeight; + _titleLabel.frame = CGRectMake(0, + (kTitleHeight-height)*0.5, + self.fs_width, + titleHeight); + + _subtitleLabel.frame = CGRectMake(0, + height-subtitleHeight, + self.fs_width, + subtitleHeight); + _subtitleLabel.textColor = [self colorForCurrentStateInDictionary:_subtitleColors]; + } else { + _titleLabel.frame = CGRectMake(0, 0, self.fs_width, floor(kTitleHeight)); + _subtitleLabel.hidden = YES; + } + if (self.calendar.dataSource && [self.calendar.dataSource respondsToSelector:@selector(calendar:hasEventForDate:)]) { + _eventLayer.hidden = [self.calendar.dataSource calendar:self.calendar hasEventForDate:_date]; + } else { + _eventLayer.hidden = YES; + } +} + +- (BOOL)isPlaceholder +{ + return !(_date.fs_year == _month.fs_year && _date.fs_month == _month.fs_month); +} + +- (BOOL)isToday +{ + return _date.fs_year == self.calendar.currentDate.fs_year && _date.fs_month == self.calendar.currentDate.fs_month && _date.fs_day == self.calendar.currentDate.fs_day; +} + +- (BOOL)isWeekend +{ + return self.date.fs_weekday == 1 || self.date.fs_weekday == 7; +} + +- (void)showAnimation +{ + _backgroundLayer.hidden = NO; + _backgroundLayer.path = [UIBezierPath bezierPathWithOvalInRect:_backgroundLayer.bounds].CGPath; + _backgroundLayer.fillColor = [self colorForCurrentStateInDictionary:_backgroundColors].CGColor; + _backgroundLayer.anchorPoint = CGPointMake(0.5, 0.5); + CAAnimationGroup *group = [CAAnimationGroup animation]; + CABasicAnimation *zoomOut = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; + zoomOut.fromValue = @0.3; + zoomOut.toValue = @1.2; + zoomOut.duration = kAnimationDuration/4*3; + CABasicAnimation *zoomIn = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; + zoomIn.fromValue = @1.2; + zoomIn.toValue = @1.0; + zoomIn.beginTime = kAnimationDuration/4*3; + zoomIn.duration = kAnimationDuration/4; + group.duration = kAnimationDuration; + group.animations = @[zoomOut, zoomIn]; + [_backgroundLayer addAnimation:group forKey:@"bounce"]; +} + +- (UIColor *)colorForCurrentStateInDictionary:(NSDictionary *)dictionary +{ + if (self.isSelected) { + return dictionary[@(FSCalendarUnitStateSelected)]; + } + if (self.isToday) { + return dictionary[@(FSCalendarUnitStateToday)]; + } + if (self.isPlaceholder) { + return dictionary[@(FSCalendarUnitStatePlaceholder)]; + } + if (self.isWeekend) { + return dictionary[@(FSCalendarUnitStateWeekend)]; + } + return dictionary[@(FSCalendarUnitStateNormal)]; +} + +@end diff --git a/Pod/Classes/FSCalendarPage.m b/Pod/Classes/FSCalendarPage.m index 30be287..1ad8fd5 100644 --- a/Pod/Classes/FSCalendarPage.m +++ b/Pod/Classes/FSCalendarPage.m @@ -57,7 +57,7 @@ - (void)updateDateForUnits { NSMutableArray *dates = [NSMutableArray arrayWithCapacity:42]; - for (int i = 0; i < _date.numberOfDaysInMonth; i++) { + for (int i = 0; i < _date.fs_numberOfDaysInMonth; i++) { [dates addObject:[NSDate fs_dateWithYear:_date.fs_year month:_date.fs_month day:i+1]]; } NSInteger numberOfPlaceholders = 42 - dates.count; diff --git a/Pod/Classes/FSCalendarUnit.m b/Pod/Classes/FSCalendarUnit.m index 9dc0a10..eb64c6c 100644 --- a/Pod/Classes/FSCalendarUnit.m +++ b/Pod/Classes/FSCalendarUnit.m @@ -120,7 +120,6 @@ _subtitleLabel.hidden = NO; _subtitleLabel.text = subtitle; CGFloat subtitleHeight = [subtitle sizeWithAttributes:@{NSFontAttributeName:self.subtitleFont}].height; - CGFloat height = titleHeight + subtitleHeight; _titleLabel.frame = CGRectMake(0, (kTitleHeight-height)*0.5, @@ -265,7 +264,6 @@ return FSCalendarUnitStateNormal; } - @end diff --git a/Pod/Classes/NSCalendar+FSExtension.h b/Pod/Classes/NSCalendar+FSExtension.h new file mode 100644 index 0000000..ec012bc --- /dev/null +++ b/Pod/Classes/NSCalendar+FSExtension.h @@ -0,0 +1,15 @@ +// +// NSCalendar+FSExtension.h +// Pods +// +// Created by Wenchao Ding on 12/3/15. +// +// + +#import + +@interface NSCalendar (FSExtension) + ++ (instancetype)fs_sharedCalendar; + +@end diff --git a/Pod/Classes/NSCalendar+FSExtension.m b/Pod/Classes/NSCalendar+FSExtension.m new file mode 100644 index 0000000..793bea7 --- /dev/null +++ b/Pod/Classes/NSCalendar+FSExtension.m @@ -0,0 +1,23 @@ +// +// NSCalendar+FSExtension.m +// Pods +// +// Created by Wenchao Ding on 12/3/15. +// +// + +#import "NSCalendar+FSExtension.h" + +@implementation NSCalendar (FSExtension) + ++ (instancetype)fs_sharedCalendar +{ + static id instance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [self currentCalendar]; + }); + return instance; +} + +@end diff --git a/Pod/Classes/NSDate+FSExtension.h b/Pod/Classes/NSDate+FSExtension.h index cdec159..6229994 100644 --- a/Pod/Classes/NSDate+FSExtension.h +++ b/Pod/Classes/NSDate+FSExtension.h @@ -15,7 +15,7 @@ @property (readonly, nonatomic) NSInteger fs_day; @property (readonly, nonatomic) NSInteger fs_weekday; -@property (readonly, nonatomic) NSInteger numberOfDaysInMonth; +@property (readonly, nonatomic) NSInteger fs_numberOfDaysInMonth; - (NSDate *)fs_dateByAddingMonths:(NSInteger)months; - (NSDate *)fs_dateBySubtractingMonths:(NSInteger)months; @@ -23,6 +23,9 @@ - (NSDate *)fs_dateBySubtractingDays:(NSInteger)days; - (NSString *)fs_stringWithFormat:(NSString *)format; +- (NSInteger)fs_yearsFrom:(NSDate *)date; +- (NSInteger)fs_monthsFrom:(NSDate *)date; + + (instancetype)fs_dateFromString:(NSString *)string format:(NSString *)format; + (instancetype)fs_dateWithYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day; diff --git a/Pod/Classes/NSDate+FSExtension.m b/Pod/Classes/NSDate+FSExtension.m index 40734b8..d6f2200 100644 --- a/Pod/Classes/NSDate+FSExtension.m +++ b/Pod/Classes/NSDate+FSExtension.m @@ -7,40 +7,41 @@ // #import "NSDate+FSExtension.h" +#import "NSCalendar+FSExtension.h" @implementation NSDate (FSExtension) - (NSInteger)fs_year { - NSCalendar *calendar = [NSCalendar currentCalendar]; + NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; NSDateComponents *component = [calendar components:NSYearCalendarUnit fromDate:self]; return component.year; } - (NSInteger)fs_month { - NSCalendar *calendar = [NSCalendar currentCalendar]; + NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; NSDateComponents *component = [calendar components:NSMonthCalendarUnit fromDate:self]; return component.month; } - (NSInteger)fs_day { - NSCalendar *calendar = [NSCalendar currentCalendar]; + NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; NSDateComponents *component = [calendar components:NSDayCalendarUnit fromDate:self]; return component.day; } - (NSInteger)fs_weekday { - NSCalendar *calendar = [NSCalendar currentCalendar]; + NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; NSDateComponents *component = [calendar components:NSWeekdayCalendarUnit fromDate:self]; return component.weekday; } -- (NSInteger)numberOfDaysInMonth +- (NSInteger)fs_numberOfDaysInMonth { - NSCalendar *c = [NSCalendar currentCalendar]; + NSCalendar *c = [NSCalendar fs_sharedCalendar]; NSRange days = [c rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:self]; @@ -56,7 +57,7 @@ - (NSDate *)fs_dateByAddingMonths:(NSInteger)months { - NSCalendar *calendar = [NSCalendar currentCalendar]; + NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; NSDateComponents *components = [[NSDateComponents alloc] init]; [components setMonth:months]; @@ -70,7 +71,7 @@ - (NSDate *)fs_dateByAddingDays:(NSInteger)days { - NSCalendar *calendar = [NSCalendar currentCalendar]; + NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; NSDateComponents *components = [[NSDateComponents alloc] init]; [components setDay:days]; return [calendar dateByAddingComponents:components toDate:self options:0]; @@ -81,6 +82,26 @@ return [self fs_dateByAddingDays:-days]; } +- (NSInteger)fs_monthsFrom:(NSDate *)date +{ + NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; + NSDateComponents *components = [calendar components:NSMonthCalendarUnit + fromDate:date + toDate:self + options:0]; + return components.month; +} + +- (NSInteger)fs_yearsFrom:(NSDate *)date +{ + NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; + NSDateComponents *components = [calendar components:NSMonthCalendarUnit + fromDate:date + toDate:self + options:0]; + return components.year; +} + + (instancetype)fs_dateFromString:(NSString *)string format:(NSString *)format { NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; @@ -90,7 +111,7 @@ + (instancetype)fs_dateWithYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day { - NSCalendar *calendar = [NSCalendar currentCalendar]; + NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; NSDateComponents *components = [[NSDateComponents alloc] init]; components.year = year; components.month = month;