From 2c3bcbbcb235afe93461d45207c52ad89a45b7b8 Mon Sep 17 00:00:00 2001 From: Wenchao Ding Date: Mon, 31 Oct 2016 22:08:10 +0800 Subject: [PATCH] Increase fps --- Example/FSCalendar.xcodeproj/project.pbxproj | 10 + ...621090AF-4CF3-4245-99AD-46AD956ACA82.plist | 22 ++ .../Info.plist | 12 + Example/FSCalendarTests/FSCalendarTests.m | 28 +- FSCalendar/FSCalendar.m | 155 ++-------- FSCalendar/FSCalendarAnimator.m | 14 +- FSCalendar/FSCalendarAppearance.m | 2 + FSCalendar/FSCalendarCalculator.h | 39 +++ FSCalendar/FSCalendarCalculator.m | 278 ++++++++++++++++++ FSCalendar/FSCalendarCell.m | 6 +- FSCalendar/FSCalendarCollectionViewLayout.m | 8 +- FSCalendar/FSCalendarDynamicHeader.h | 11 +- FSCalendar/FSCalendarExtensions.h | 7 + FSCalendar/FSCalendarExtensions.m | 20 ++ 14 files changed, 453 insertions(+), 159 deletions(-) create mode 100644 Example/FSCalendar.xcodeproj/xcshareddata/xcbaselines/30671DC61D6D574C00BCFC4E.xcbaseline/621090AF-4CF3-4245-99AD-46AD956ACA82.plist create mode 100644 FSCalendar/FSCalendarCalculator.h create mode 100644 FSCalendar/FSCalendarCalculator.m diff --git a/Example/FSCalendar.xcodeproj/project.pbxproj b/Example/FSCalendar.xcodeproj/project.pbxproj index 0d83943..4ba7191 100644 --- a/Example/FSCalendar.xcodeproj/project.pbxproj +++ b/Example/FSCalendar.xcodeproj/project.pbxproj @@ -49,6 +49,9 @@ 30CEF9011C950C1F008EAFB1 /* FSCalendarAnimator.m in Sources */ = {isa = PBXBuildFile; fileRef = 30CEF8FF1C950C1F008EAFB1 /* FSCalendarAnimator.m */; }; 30CEF9021C950C1F008EAFB1 /* FSCalendarAnimator.m in Sources */ = {isa = PBXBuildFile; fileRef = 30CEF8FF1C950C1F008EAFB1 /* FSCalendarAnimator.m */; }; 30D55B101C90240000BB43D5 /* HidePlaceholderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 30D55B0F1C90240000BB43D5 /* HidePlaceholderViewController.m */; }; + 30DBE3C41DC641AD005A22B7 /* FSCalendarCalculator.h in Headers */ = {isa = PBXBuildFile; fileRef = 30DBE3C21DC641AD005A22B7 /* FSCalendarCalculator.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 30DBE3C51DC641AD005A22B7 /* FSCalendarCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = 30DBE3C31DC641AD005A22B7 /* FSCalendarCalculator.m */; }; + 30DBE3C61DC641AD005A22B7 /* FSCalendarCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = 30DBE3C31DC641AD005A22B7 /* FSCalendarCalculator.m */; }; 30F5D8561B9FC33400C1C201 /* FSCalendar.m in Sources */ = {isa = PBXBuildFile; fileRef = 30B0BAC01B8D8E22004B9476 /* FSCalendar.m */; }; 30F5D85A1B9FC4BB00C1C201 /* MultipleSelectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 30F5D8591B9FC4BB00C1C201 /* MultipleSelectionViewController.m */; }; 30FCB3961BAAD112002B87AD /* FSCalendarStickyHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 30FCB3941BAAD112002B87AD /* FSCalendarStickyHeader.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -135,6 +138,8 @@ 30CEF8FF1C950C1F008EAFB1 /* FSCalendarAnimator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSCalendarAnimator.m; sourceTree = ""; }; 30D55B0E1C90240000BB43D5 /* HidePlaceholderViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HidePlaceholderViewController.h; sourceTree = SOURCE_ROOT; }; 30D55B0F1C90240000BB43D5 /* HidePlaceholderViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HidePlaceholderViewController.m; sourceTree = SOURCE_ROOT; }; + 30DBE3C21DC641AD005A22B7 /* FSCalendarCalculator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSCalendarCalculator.h; sourceTree = ""; }; + 30DBE3C31DC641AD005A22B7 /* FSCalendarCalculator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSCalendarCalculator.m; sourceTree = ""; }; 30F5D8581B9FC4BB00C1C201 /* MultipleSelectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MultipleSelectionViewController.h; sourceTree = SOURCE_ROOT; }; 30F5D8591B9FC4BB00C1C201 /* MultipleSelectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MultipleSelectionViewController.m; sourceTree = SOURCE_ROOT; }; 30FCB3941BAAD112002B87AD /* FSCalendarStickyHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSCalendarStickyHeader.h; sourceTree = ""; }; @@ -226,6 +231,8 @@ 30B0BAC21B8D8E22004B9476 /* FSCalendarAppearance.m */, 303105F11DC241D9002F802F /* FSCalendarDelegateProxy.h */, 303105F21DC241D9002F802F /* FSCalendarDelegateProxy.m */, + 30DBE3C21DC641AD005A22B7 /* FSCalendarCalculator.h */, + 30DBE3C31DC641AD005A22B7 /* FSCalendarCalculator.m */, 309225381B905C4300123031 /* FSCalendarConstants.h */, 309225391B905C4300123031 /* FSCalendarConstants.m */, 3065CA941CD31B81006C218D /* FSCalendarScopeHandle.h */, @@ -405,6 +412,7 @@ 3065CA961CD31B81006C218D /* FSCalendarScopeHandle.h in Headers */, 3095398F1C38D66C00BD37AA /* FSCalendarCollectionViewLayout.h in Headers */, 3055B1C21DA9323A002AFA13 /* FSCalendarExtensions.h in Headers */, + 30DBE3C41DC641AD005A22B7 /* FSCalendarCalculator.h in Headers */, 30CEF9001C950C1F008EAFB1 /* FSCalendarAnimator.h in Headers */, 30B0BB031B8D9B6D004B9476 /* FSCalendarDynamicHeader.h in Headers */, ); @@ -558,6 +566,7 @@ files = ( EE638CCE1B89DBD80006DD1A /* StoryboardExampleViewController.m in Sources */, EECA10F81BA9C0E400945B83 /* FullScreenExampleViewController.m in Sources */, + 30DBE3C51DC641AD005A22B7 /* FSCalendarCalculator.m in Sources */, EE638CC91B89DB940006DD1A /* CalendarConfigViewController.m in Sources */, 30B0BAD01B8D8E23004B9476 /* FSCalendar.m in Sources */, 3065CAA81CD3506A006C218D /* FSCalendar+Deprecated.m in Sources */, @@ -595,6 +604,7 @@ EEC9C03B1BDC9E7000383A07 /* FSCalendarCollectionView.m in Sources */, 3065CAA91CD3506A006C218D /* FSCalendar+Deprecated.m in Sources */, 30B0BAF71B8D9AC1004B9476 /* FSCalendarCell.m in Sources */, + 30DBE3C61DC641AD005A22B7 /* FSCalendarCalculator.m in Sources */, 30B0BAF81B8D9AC1004B9476 /* FSCalendarHeader.m in Sources */, 3092253C1B905C4300123031 /* FSCalendarConstants.m in Sources */, 3055B1C41DA9323A002AFA13 /* FSCalendarExtensions.m in Sources */, diff --git a/Example/FSCalendar.xcodeproj/xcshareddata/xcbaselines/30671DC61D6D574C00BCFC4E.xcbaseline/621090AF-4CF3-4245-99AD-46AD956ACA82.plist b/Example/FSCalendar.xcodeproj/xcshareddata/xcbaselines/30671DC61D6D574C00BCFC4E.xcbaseline/621090AF-4CF3-4245-99AD-46AD956ACA82.plist new file mode 100644 index 0000000..f526a7d --- /dev/null +++ b/Example/FSCalendar.xcodeproj/xcshareddata/xcbaselines/30671DC61D6D574C00BCFC4E.xcbaseline/621090AF-4CF3-4245-99AD-46AD956ACA82.plist @@ -0,0 +1,22 @@ + + + + + classNames + + FSCalendarTests + + testIndexPathForDatePerformance + + com.apple.XCTPerformanceMetric_WallClockTime + + baselineAverage + 0 + baselineIntegrationDisplayName + Local Baseline + + + + + + diff --git a/Example/FSCalendar.xcodeproj/xcshareddata/xcbaselines/30671DC61D6D574C00BCFC4E.xcbaseline/Info.plist b/Example/FSCalendar.xcodeproj/xcshareddata/xcbaselines/30671DC61D6D574C00BCFC4E.xcbaseline/Info.plist index b0439d4..b7d2e25 100644 --- a/Example/FSCalendar.xcodeproj/xcshareddata/xcbaselines/30671DC61D6D574C00BCFC4E.xcbaseline/Info.plist +++ b/Example/FSCalendar.xcodeproj/xcshareddata/xcbaselines/30671DC61D6D574C00BCFC4E.xcbaseline/Info.plist @@ -35,6 +35,18 @@ com.apple.platform.iphonesimulator + 621090AF-4CF3-4245-99AD-46AD956ACA82 + + targetArchitecture + arm64 + targetDevice + + modelCode + iPhone8,4 + platformIdentifier + com.apple.platform.iphoneos + + A165CA85-3EFC-487B-954E-5AD1DC2EB21D localComputer diff --git a/Example/FSCalendarTests/FSCalendarTests.m b/Example/FSCalendarTests/FSCalendarTests.m index 5f0d3f4..f22048d 100644 --- a/Example/FSCalendarTests/FSCalendarTests.m +++ b/Example/FSCalendarTests/FSCalendarTests.m @@ -9,12 +9,14 @@ #import #import "FSCalendar.h" #import "FSCalendarDynamicHeader.h" +#import "FSCalendarExtensions.h" -@interface FSCalendarTests : XCTestCase +@interface FSCalendarTests : XCTestCase @property (strong, nonatomic) FSCalendar *calendar; @property (strong, nonatomic) NSDate *date; @property (strong, nonatomic) NSIndexPath *indexPath; +@property (strong, nonatomic) NSMutableArray *indexPaths; @property (strong, nonatomic) NSDateFormatter *formatter; @end @@ -25,13 +27,29 @@ { [super setUp]; self.calendar = [[FSCalendar alloc] initWithFrame:CGRectMake(0, 0, 320, 300)]; + [self.calendar.calculator reloadSections]; self.indexPath = [NSIndexPath indexPathForItem:25 inSection:0]; - self.date = [self.calendar dateForIndexPath:self.indexPath]; + + self.indexPaths = [NSMutableArray array]; + for (int i = 0; i < 42; i++) { + [self.indexPaths addObject:[NSIndexPath indexPathForItem:i inSection:0]]; + } self.formatter = [[NSDateFormatter alloc] init]; self.formatter.dateFormat = @"yyyy-MM-dd"; + self.date = [self.formatter dateFromString:@"1900-11-11"]; } +- (NSDate *)minimumDateForCalendar:(FSCalendar *)calendar +{ + return [self.formatter dateFromString:@"1900-01-01"]; +} + +- (NSDate *)maximumDateForCalendar:(FSCalendar *)calendar +{ + return [self.formatter dateFromString:@"2300-01-01"]; +} + - (void)tearDown { [super tearDown]; @@ -48,13 +66,15 @@ - (void)testIndexPathForDatePerformance { [self measureBlock:^{ - [self.calendar indexPathForDate:self.date scope:FSCalendarScopeMonth]; + [self.calendar.calculator indexPathForDate:self.date scope:FSCalendarScopeMonth]; }]; } - (void)testDateForIndexPathPerformance { [self measureBlock:^{ - [self.calendar dateForIndexPath:self.indexPath]; + [self.indexPaths enumerateObjectsUsingBlock:^(NSIndexPath * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + [self.calendar.calculator dateForIndexPath:obj]; + }]; }]; } diff --git a/FSCalendar/FSCalendar.m b/FSCalendar/FSCalendar.m index 927913f..44901dc 100644 --- a/FSCalendar/FSCalendar.m +++ b/FSCalendar/FSCalendar.m @@ -19,6 +19,7 @@ #import "FSCalendarAnimator.h" #import "FSCalendarDelegateProxy.h" +#import "FSCalendarCalculator.h" NS_ASSUME_NONNULL_BEGIN @@ -65,8 +66,9 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { @property (weak , nonatomic) FSCalendarCollectionView *collectionView; @property (weak , nonatomic) FSCalendarCollectionViewLayout *collectionViewLayout; -@property (strong, nonatomic) FSCalendarAnimator *animator; -@property (strong, nonatomic) FSCalendarDelegateProxy *proxy; +@property (strong, nonatomic) FSCalendarAnimator *animator; +@property (strong, nonatomic) FSCalendarDelegateProxy *proxy; +@property (strong, nonatomic) FSCalendarCalculator *calculator; @property (weak , nonatomic) FSCalendarHeader *header; @property (weak , nonatomic) FSCalendarHeaderTouchDeliver *deliver; @@ -92,13 +94,8 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { - (void)orientationDidChange:(NSNotification *)notification; -- (NSDate *)dateForIndexPath:(NSIndexPath *)indexPath; -- (NSDate *)dateForIndexPath:(NSIndexPath *)indexPath scope:(FSCalendarScope)scope; -- (NSIndexPath *)indexPathForDate:(NSDate *)date; -- (NSIndexPath *)indexPathForDate:(NSDate *)date scope:(FSCalendarScope)scope; - (CGSize)sizeThatFits:(CGSize)size scope:(FSCalendarScope)scope; -- (NSInteger)numberOfHeadPlaceholdersForMonth:(NSDate *)month; - (NSInteger)numberOfRowsInMonth:(NSDate *)month; - (void)scrollToDate:(NSDate *)date; @@ -133,8 +130,6 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { - (void)requestBoundingDatesIfNecessary; -- (NSDate *)safeDateForDate:(NSDate *)date; - @end @implementation FSCalendar @@ -264,6 +259,7 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { // Assistants self.animator = [[FSCalendarAnimator alloc] initWithCalendar:self]; self.proxy = [[FSCalendarDelegateProxy alloc] initWithCalendar:self]; + self.calculator = [[FSCalendarCalculator alloc] initWithCalendar:self]; // Gestures UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self.animator action:@selector(handlePan:)]; @@ -483,20 +479,7 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { [self requestBoundingDatesIfNecessary]; - if (self.animator.transition == FSCalendarTransitionWeekToMonth) { - NSInteger sections = [self.gregorian components:NSCalendarUnitMonth fromDate:[self.gregorian fs_firstDayOfMonth:self.minimumDate] toDate:self.maximumDate options:0].month + 1; - return sections; - } - switch (_scope) { - case FSCalendarScopeMonth: { - NSInteger sections = [self.gregorian components:NSCalendarUnitMonth fromDate:[self.gregorian fs_firstDayOfMonth:self.minimumDate] toDate:self.maximumDate options:0].month + 1; - return sections; - } - case FSCalendarScopeWeek: { - NSInteger sections = [self.gregorian components:NSCalendarUnitWeekOfYear fromDate:[self.gregorian fs_firstDayOfWeek:self.minimumDate] toDate:self.maximumDate options:0].weekOfYear + 1; - return sections; - } - } + return self.calculator.numberOfSections; } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section @@ -556,7 +539,7 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { FSCalendarCell *cell = (FSCalendarCell *)[collectionView cellForItemAtIndexPath:indexPath]; cell.dateIsSelected = YES; [cell performSelecting]; - NSDate *selectedDate = [self dateForIndexPath:indexPath]; + NSDate *selectedDate = [self.calculator dateForIndexPath:indexPath]; if (!_supressEvent) { [self.proxy didSelectDate:selectedDate]; } @@ -573,7 +556,7 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { } return NO; } - NSDate *targetDate = [self dateForIndexPath:indexPath]; + NSDate *targetDate = [self.calculator dateForIndexPath:indexPath]; if ([self isDateSelected:targetDate]) { // Click on a selected date in multiple-selection mode if (self.allowsMultipleSelection) { @@ -597,7 +580,7 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { - (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath { if (!self.allowsMultipleSelection && self.selectedDate) { - NSIndexPath *selectedIndexPath = [self indexPathForDate:self.selectedDate]; + NSIndexPath *selectedIndexPath = [self.calculator indexPathForDate:self.selectedDate]; if (![indexPath isEqual:selectedIndexPath]) { [self collectionView:collectionView didDeselectItemAtIndexPath:selectedIndexPath]; return; @@ -608,7 +591,7 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { cell.dateIsSelected = NO; [cell setNeedsLayout]; } - NSDate *selectedDate = cell.date ?: [self dateForIndexPath:indexPath]; + NSDate *selectedDate = cell.date ?: [self.calculator dateForIndexPath:indexPath]; [_selectedDates removeObject:selectedDate]; [self deselectCounterpartDate:selectedDate]; [self.proxy didDeselectDate:selectedDate]; @@ -617,13 +600,13 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { - (BOOL)collectionView:(UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath { if (!self.allowsMultipleSelection) { - NSIndexPath *selectedIndexPath = [self indexPathForDate:self.selectedDate]; + NSIndexPath *selectedIndexPath = [self.calculator indexPathForDate:self.selectedDate]; if (![indexPath isEqual:selectedIndexPath]) { return [self collectionView:collectionView shouldDeselectItemAtIndexPath:selectedIndexPath]; } } FSCalendarCell *cell = (FSCalendarCell *)[collectionView cellForItemAtIndexPath:indexPath]; - return [self.proxy shouldDeselectDate:(cell.date?:[self dateForIndexPath:indexPath])]; + return [self.proxy shouldDeselectDate:(cell.date?:[self.calculator dateForIndexPath:indexPath])]; } - (void)collectionView:(UICollectionView *)collectionView willDisplaySupplementaryView:(UICollectionReusableView *)view forElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath @@ -816,7 +799,7 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { } if (self.hasValidateVisibleLayout) { [_collectionView.visibleCells makeObjectsPerformSelector:@selector(setDateIsToday:) withObject:@NO]; - [[_collectionView cellForItemAtIndexPath:[self indexPathForDate:today]] setValue:@YES forKey:@"dateIsToday"]; + [[_collectionView cellForItemAtIndexPath:[self.calculator indexPathForDate:today]] setValue:@YES forKey:@"dateIsToday"]; [_collectionView.visibleCells makeObjectsPerformSelector:@selector(setNeedsLayout)]; } } @@ -842,7 +825,7 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { if (!self.superview) { return CGRectZero; } - CGRect frame = [_collectionViewLayout layoutAttributesForItemAtIndexPath:[self indexPathForDate:date]].frame; + CGRect frame = [_collectionViewLayout layoutAttributesForItemAtIndexPath:[self.calculator indexPathForDate:date]].frame; frame = [self.superview convertRect:frame fromView:_collectionView]; return frame; } @@ -1132,7 +1115,7 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { return; } [_selectedDates removeObject:date]; - NSIndexPath *indexPath = [self indexPathForDate:date]; + NSIndexPath *indexPath = [self.calculator indexPathForDate:date]; if ([_collectionView.indexPathsForSelectedItems containsObject:indexPath]) { [_collectionView deselectItemAtIndexPath:indexPath animated:YES]; FSCalendarCell *cell = (FSCalendarCell *)[_collectionView cellForItemAtIndexPath:indexPath]; @@ -1152,7 +1135,7 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { FSCalendarAssertDateInBounds(date,self.gregorian,self.minimumDate,self.maximumDate); NSDate *targetDate = [self.gregorian dateBySettingHour:0 minute:0 second:0 ofDate:date options:0]; - NSIndexPath *targetIndexPath = [self indexPathForDate:targetDate]; + NSIndexPath *targetIndexPath = [self.calculator indexPathForDate:targetDate]; BOOL shouldSelect = !_supressEvent; // 跨月份点击 @@ -1284,7 +1267,7 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { { if (!date) return; if (![self isDateInRange:date]) { - date = [self safeDateForDate:date]; + date = [self.calculator safeDateForDate:date]; if (!date) return; } @@ -1318,87 +1301,6 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { } } -- (NSDate *)dateForIndexPath:(NSIndexPath *)indexPath scope:(FSCalendarScope)scope -{ - if (!indexPath) return nil; - switch (scope) { - case FSCalendarScopeMonth: { - NSDate *currentPage = [self.gregorian dateByAddingUnit:NSCalendarUnitMonth value:indexPath.section toDate:[self.gregorian fs_firstDayOfMonth:_minimumDate] options:0]; - NSInteger numberOfHeadPlaceholders = [self numberOfHeadPlaceholdersForMonth:currentPage]; - NSDate *firstDateOfPage = [self.gregorian dateByAddingUnit:NSCalendarUnitDay value:-numberOfHeadPlaceholders toDate:currentPage options:0]; - switch (_collectionViewLayout.scrollDirection) { - case UICollectionViewScrollDirectionHorizontal: { - NSUInteger rows = indexPath.item % 6; - NSUInteger columns = indexPath.item / 6; - NSUInteger daysOffset = 7*rows + columns; - NSDate *date = [self.gregorian dateByAddingUnit:NSCalendarUnitDay value:daysOffset toDate:firstDateOfPage options:0]; - return date; - } - case UICollectionViewScrollDirectionVertical: { - NSUInteger daysOffset = indexPath.item; - NSDate *date = [self.gregorian dateByAddingUnit:NSCalendarUnitDay value:daysOffset toDate:firstDateOfPage options:0]; - return date; - } - } - break; - } - case FSCalendarScopeWeek: { - NSDate *currentPage = [self.gregorian dateByAddingUnit:NSCalendarUnitWeekOfYear value:indexPath.section toDate:[self.gregorian fs_firstDayOfWeek:_minimumDate] options:0]; - NSDate *date = [self.gregorian dateByAddingUnit:NSCalendarUnitDay value:indexPath.item toDate:currentPage options:0]; - return date; - - } - } - return nil; -} - -- (NSDate *)dateForIndexPath:(NSIndexPath *)indexPath -{ - if (self.animator.transition == FSCalendarTransitionWeekToMonth && self.animator.state == FSCalendarTransitionStateInProgress) { - return [self dateForIndexPath:indexPath scope:FSCalendarScopeMonth]; - } - return [self dateForIndexPath:indexPath scope:_scope]; -} - -- (NSIndexPath *)indexPathForDate:(NSDate *)date scope:(FSCalendarScope)scope -{ - if (!date) return nil; - NSInteger item = 0; - NSInteger section = 0; - switch (scope) { - case FSCalendarScopeMonth: { - section = [self.gregorian components:NSCalendarUnitMonth fromDate:[self.gregorian fs_firstDayOfMonth:self.minimumDate] toDate:date options:0].month; - NSDate *firstDayOfMonth = [self.gregorian fs_firstDayOfMonth:date]; - NSInteger numberOfHeadPlaceholders = [self numberOfHeadPlaceholdersForMonth:firstDayOfMonth]; - NSDate *firstDateOfPage = [self.gregorian dateByAddingUnit:NSCalendarUnitDay value:-numberOfHeadPlaceholders toDate:firstDayOfMonth options:0]; - switch (_collectionViewLayout.scrollDirection) { - case UICollectionViewScrollDirectionHorizontal: { - NSInteger vItem = [self.gregorian components:NSCalendarUnitDay fromDate:firstDateOfPage toDate:date options:0].day; - NSInteger rows = vItem/7; - NSInteger columns = vItem%7; - item = columns*6 + rows; - break; - } - case UICollectionViewScrollDirectionVertical: { - item = [self.gregorian components:NSCalendarUnitDay fromDate:firstDateOfPage toDate:date options:0].day; - break; - } - } - break; - } - case FSCalendarScopeWeek: { - section = [self.gregorian components:NSCalendarUnitWeekOfYear fromDate:[self.gregorian fs_firstDayOfWeek:self.minimumDate] toDate:date options:0].weekOfYear; - item = (([self.gregorian component:NSCalendarUnitWeekday fromDate:date] - _firstWeekday) + 7) % 7; - break; - } - } - return [NSIndexPath indexPathForItem:item inSection:section]; -} - -- (NSIndexPath *)indexPathForDate:(NSDate *)date -{ - return [self indexPathForDate:date scope:_scope]; -} - (BOOL)isDateInRange:(NSDate *)date { @@ -1436,7 +1338,7 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { - (BOOL)isDateSelected:(NSDate *)date { - return [_selectedDates containsObject:date] || [_collectionView.indexPathsForSelectedItems containsObject:[self indexPathForDate:date]]; + return [_selectedDates containsObject:date] || [_collectionView.indexPathsForSelectedItems containsObject:[self.calculator indexPathForDate:date]]; } - (BOOL)isDateInDifferentPage:(NSDate *)date @@ -1620,7 +1522,7 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { - (void)reloadDataForCell:(FSCalendarCell *)cell atIndexPath:(NSIndexPath *)indexPath { cell.calendar = self; - cell.date = [self dateForIndexPath:indexPath]; + cell.date = [self.calculator dateForIndexPath:indexPath]; cell.image = [self.proxy imageForDate:cell.date]; cell.numberOfEvents = [self.proxy numberOfEventsForDate:cell.date]; cell.title = [self.proxy titleForDate:cell.date]; @@ -1778,13 +1680,6 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { return orientation; } -- (NSInteger)numberOfHeadPlaceholdersForMonth:(NSDate *)month -{ - NSInteger currentWeekday = [self.gregorian component:NSCalendarUnitWeekday fromDate:month]; - NSInteger number = ((currentWeekday- _firstWeekday) + 7) % 7 ?: (7 * (!self.floatingMode&&(self.placeholderType == FSCalendarPlaceholderTypeFillSixRows))); - return number; -} - - (NSInteger)numberOfRowsInMonth:(NSDate *)month { if (!month) return 0; @@ -1805,19 +1700,11 @@ typedef NS_ENUM(NSUInteger, FSCalendarOrientation) { _minimumDate = self.proxy.minimumDateForCalendar; _maximumDate = self.proxy.maximumDateForCalendar; NSAssert([self.gregorian compareDate:self.minimumDate toDate:self.maximumDate toUnitGranularity:NSCalendarUnitDay] != NSOrderedDescending, @"The minimum date of calendar should be earlier than the maximum."); + [self.calculator reloadSections]; + } } -- (NSDate *)safeDateForDate:(NSDate *)date -{ - if ([self.gregorian compareDate:date toDate:self.minimumDate toUnitGranularity:NSCalendarUnitDay] == NSOrderedAscending) { - date = self.minimumDate; - } else if ([self.gregorian compareDate:date toDate:self.maximumDate toUnitGranularity:NSCalendarUnitDay] == NSOrderedDescending) { - date = self.maximumDate; - } - return date; -} - @end diff --git a/FSCalendar/FSCalendarAnimator.m b/FSCalendar/FSCalendarAnimator.m index d9fe536..7a0bd89 100644 --- a/FSCalendar/FSCalendarAnimator.m +++ b/FSCalendar/FSCalendarAnimator.m @@ -313,8 +313,8 @@ - (void)performBoundingRectTransitionFromMonth:(NSDate *)fromMonth toMonth:(NSDate *)toMonth duration:(CGFloat)duration { if (self.calendarScope != FSCalendarScopeMonth) return; - NSInteger lastRowCount = [self.calendar numberOfRowsInMonth:fromMonth]; - NSInteger currentRowCount = [self.calendar numberOfRowsInMonth:toMonth]; + NSInteger lastRowCount = [self.calendar.calculator numberOfRowsInMonth:fromMonth]; + NSInteger currentRowCount = [self.calendar.calculator numberOfRowsInMonth:toMonth]; if (lastRowCount != currentRowCount) { CGFloat animationDuration = duration; CGRect bounds = (CGRect){CGPointZero,[self.calendar sizeThatFits:self.calendar.frame.size scope:FSCalendarScopeMonth]}; @@ -399,7 +399,7 @@ #define kCalculateRowNumber \ do { \ - UICollectionViewLayoutAttributes *itemAttributes = [self.collectionViewLayout layoutAttributesForItemAtIndexPath:[self.calendar indexPathForDate:focusedDate scope:FSCalendarScopeMonth]]; \ + UICollectionViewLayoutAttributes *itemAttributes = [self.collectionViewLayout layoutAttributesForItemAtIndexPath:[self.calendar.calculator indexPathForDate:focusedDate scope:FSCalendarScopeMonth]]; \ CGPoint focuedCenter = itemAttributes.center; \ if (CGRectContainsPoint(self.collectionView.bounds, focuedCenter)) { \ switch (self.collectionViewLayout.scrollDirection) { \ @@ -434,7 +434,7 @@ NSDate *minimumPage = [self.calendar.gregorian fs_firstDayOfMonth:self.calendar.minimumDate]; NSInteger visibleSection = [self.calendar.gregorian components:NSCalendarUnitMonth fromDate:minimumPage toDate:currentPage options:0].month; NSIndexPath *firstIndexPath = [NSIndexPath indexPathForItem:0 inSection:visibleSection]; - NSDate *firstDate = [self.calendar dateForIndexPath:firstIndexPath scope:FSCalendarScopeMonth]; + NSDate *firstDate = [self.calendar.calculator dateForIndexPath:firstIndexPath scope:FSCalendarScopeMonth]; currentPage = [self.calendar.gregorian dateByAddingUnit:NSCalendarUnitDay value:focusedRowNumber*7 toDate:firstDate options:0]; attributes.focusedRowNumber = focusedRowNumber; @@ -455,7 +455,7 @@ NSDate *focusedDate = self.calendar.selectedDate ?: self.calendar.today; if (focusedDate) { - UICollectionViewLayoutAttributes *itemAttributes = [self.collectionViewLayout layoutAttributesForItemAtIndexPath:[self.calendar indexPathForDate:focusedDate scope:FSCalendarScopeWeek]]; + UICollectionViewLayoutAttributes *itemAttributes = [self.collectionViewLayout layoutAttributesForItemAtIndexPath:[self.calendar.calculator indexPathForDate:focusedDate scope:FSCalendarScopeWeek]]; CGPoint focuedCenter = itemAttributes.center; if (!CGRectContainsPoint(self.calendar.collectionView.bounds, focuedCenter)) { focusedDate = nil; @@ -468,7 +468,7 @@ NSDate *firstDayOfMonth = [self.calendar.gregorian fs_firstDayOfMonth:focusedDate]; attributes.focusedDate = focusedDate; firstDayOfMonth = firstDayOfMonth ?: [self.calendar.gregorian fs_firstDayOfMonth:currentPage]; - NSInteger numberOfPlaceholdersForPrev = [self.calendar numberOfHeadPlaceholdersForMonth:firstDayOfMonth]; + NSInteger numberOfPlaceholdersForPrev = [self.calendar.calculator numberOfHeadPlaceholdersForMonth:firstDayOfMonth]; NSDate *firstDateOfPage = [self.calendar.gregorian dateByAddingUnit:NSCalendarUnitDay value:-numberOfPlaceholdersForPrev toDate:firstDayOfMonth options:0]; for (int i = 0; i < 6; i++) { @@ -534,7 +534,7 @@ self.calendar.preferredHeaderHeight+ self.calendar.preferredWeekdayHeight+ self.calendar.preferredPadding*2+ - ([self.calendar numberOfRowsInMonth:page]*self.calendar.preferredRowHeight)+ + ([self.calendar.calculator numberOfRowsInMonth:page]*self.calendar.preferredRowHeight)+ self.calendar.scopeHandle.fs_height); } break; diff --git a/FSCalendar/FSCalendarAppearance.m b/FSCalendar/FSCalendarAppearance.m index 57b31cf..b96375a 100644 --- a/FSCalendar/FSCalendarAppearance.m +++ b/FSCalendar/FSCalendarAppearance.m @@ -657,11 +657,13 @@ - (void)invalidateTitleFont { [_calendar.collectionView.visibleCells makeObjectsPerformSelector:_cmd]; + _calendar.calculator.titleHeight = -1; } - (void)invalidateSubtitleFont { [_calendar.collectionView.visibleCells makeObjectsPerformSelector:_cmd]; + _calendar.calculator.subtitleHeight = -1; } - (void)invalidateTitleTextColor diff --git a/FSCalendar/FSCalendarCalculator.h b/FSCalendar/FSCalendarCalculator.h new file mode 100644 index 0000000..523a1d0 --- /dev/null +++ b/FSCalendar/FSCalendarCalculator.h @@ -0,0 +1,39 @@ +// +// FSCalendarCalculator.h +// FSCalendar +// +// Created by dingwenchao on 30/10/2016. +// Copyright © 2016 wenchaoios. All rights reserved. +// + +#import +#import + +@class FSCalendar; + +@interface FSCalendarCalculator : NSObject + +@property (weak , nonatomic) FSCalendar *calendar; + +@property (assign, nonatomic) CGFloat monthHeight; +@property (assign, nonatomic) CGFloat titleHeight; +@property (assign, nonatomic) CGFloat subtitleHeight; + +@property (readonly, nonatomic) NSInteger numberOfSections; + +- (instancetype)initWithCalendar:(FSCalendar *)calendar; + +- (NSDate *)safeDateForDate:(NSDate *)date; + +- (NSDate *)dateForIndexPath:(NSIndexPath *)indexPath; +- (NSDate *)dateForIndexPath:(NSIndexPath *)indexPath scope:(FSCalendarScope)scope; +- (NSIndexPath *)indexPathForDate:(NSDate *)date; +- (NSIndexPath *)indexPathForDate:(NSDate *)date scope:(FSCalendarScope)scope; + +- (NSInteger)numberOfHeadPlaceholdersForMonth:(NSDate *)month; +- (NSInteger)numberOfRowsInMonth:(NSDate *)month; +- (NSInteger)numberOfRowsInSection:(NSInteger)section; + +- (void)reloadSections; + +@end diff --git a/FSCalendar/FSCalendarCalculator.m b/FSCalendar/FSCalendarCalculator.m new file mode 100644 index 0000000..7ab83d3 --- /dev/null +++ b/FSCalendar/FSCalendarCalculator.m @@ -0,0 +1,278 @@ +// +// FSCalendarCalculator.m +// FSCalendar +// +// Created by dingwenchao on 30/10/2016. +// Copyright © 2016 wenchaoios. All rights reserved. +// + +#import "FSCalendar.h" +#import "FSCalendarCalculator.h" +#import "FSCalendarDynamicHeader.h" +#import "FSCalendarExtensions.h" + +@interface FSCalendarCalculator () + +@property (assign, nonatomic) NSInteger numberOfMonths; +@property (strong, nonatomic) NSCache *months; +@property (strong, nonatomic) NSCache *monthHeads; + +@property (assign, nonatomic) NSInteger numberOfWeeks; +@property (strong, nonatomic) NSCache *weeks; + +@property (strong, nonatomic) NSCache *rowNumbers; + +@property (readonly, nonatomic) NSCalendar *gregorian; +@property (readonly, nonatomic) NSDate *minimumDate; +@property (readonly, nonatomic) NSDate *maximumDate; + +- (NSDate *)weekForSection:(NSInteger)section; +- (NSDate *)monthForSection:(NSInteger)section; +- (NSDate *)monthHeadForSection:(NSInteger)section; + +@end + +@implementation FSCalendarCalculator + +- (instancetype)initWithCalendar:(FSCalendar *)calendar +{ + self = [super init]; + if (self) { + self.calendar = calendar; + self.monthHeight = -1; + self.titleHeight = -1; + self.subtitleHeight = -1; + + self.months = [[NSCache alloc] init]; + self.months.countLimit = 40; + self.months.delegate = self; + self.monthHeads = [[NSCache alloc] init]; + self.monthHeads.countLimit = 40; + self.monthHeads.delegate = self; + + self.weeks = [[NSCache alloc] init]; + self.weeks.countLimit = 30; + self.weeks.delegate = self; + + self.rowNumbers = [[NSCache alloc] init]; + self.rowNumbers.countLimit = 40; + self.rowNumbers.delegate = self; + } + return self; +} + +#pragma mark - + +- (void)cache:(NSCache *)cache willEvictObject:(id)obj { } + +#pragma mark - Public methods + +- (CGFloat)titleHeight +{ + if (_titleHeight == -1) { + _titleHeight = [@"1" sizeWithAttributes:@{NSFontAttributeName:self.calendar.appearance.titleFont}].height; + } + return _titleHeight; +} + +- (CGFloat)subtitleHeight +{ + if (_subtitleHeight == -1) { + _subtitleHeight = [@"1" sizeWithAttributes:@{NSFontAttributeName:self.calendar.appearance.subtitleFont}].height; + } + return _subtitleHeight; +} + +- (NSDate *)safeDateForDate:(NSDate *)date +{ + if ([self.gregorian compareDate:date toDate:self.minimumDate toUnitGranularity:NSCalendarUnitDay] == NSOrderedAscending) { + date = self.minimumDate; + } else if ([self.gregorian compareDate:date toDate:self.maximumDate toUnitGranularity:NSCalendarUnitDay] == NSOrderedDescending) { + date = self.maximumDate; + } + return date; +} + +- (NSDate *)dateForIndexPath:(NSIndexPath *)indexPath scope:(FSCalendarScope)scope +{ + if (!indexPath) return nil; + switch (scope) { + case FSCalendarScopeMonth: { + NSDate *head = [self monthHeadForSection:indexPath.section]; + switch (self.calendar.collectionViewLayout.scrollDirection) { + case UICollectionViewScrollDirectionHorizontal: { + NSUInteger rows = indexPath.item % 6; + NSUInteger columns = indexPath.item / 6; + NSUInteger daysOffset = 7*rows + columns; + NSDate *date = [self.gregorian dateByAddingUnit:NSCalendarUnitDay value:daysOffset toDate:head options:0]; + return date; + } + case UICollectionViewScrollDirectionVertical: { + NSUInteger daysOffset = indexPath.item; + NSDate *date = [self.gregorian dateByAddingUnit:NSCalendarUnitDay value:daysOffset toDate:head options:0]; + return date; + } + } + break; + } + case FSCalendarScopeWeek: { + NSDate *currentPage = [self weekForSection:indexPath.section]; + NSDate *date = [self.gregorian dateByAddingUnit:NSCalendarUnitDay value:indexPath.item toDate:currentPage options:0]; + return date; + } + } + return nil; +} + +- (NSDate *)dateForIndexPath:(NSIndexPath *)indexPath +{ + if (self.calendar.animator.transition == FSCalendarTransitionWeekToMonth && self.calendar.animator.state == FSCalendarTransitionStateInProgress) { + return [self dateForIndexPath:indexPath scope:FSCalendarScopeMonth]; + } + return [self dateForIndexPath:indexPath scope:self.calendar.scope]; +} + +- (NSIndexPath *)indexPathForDate:(NSDate *)date scope:(FSCalendarScope)scope +{ + if (!date) return nil; + NSInteger item = 0; + NSInteger section = 0; + switch (scope) { + case FSCalendarScopeMonth: { + section = [self.gregorian components:NSCalendarUnitMonth fromDate:[self.gregorian fs_firstDayOfMonth:self.minimumDate] toDate:date options:0].month; + NSDate *head = [self monthHeadForSection:section]; + switch (self.calendar.collectionViewLayout.scrollDirection) { + case UICollectionViewScrollDirectionHorizontal: { + NSInteger vItem = [self.gregorian components:NSCalendarUnitDay fromDate:head toDate:date options:0].day; + NSInteger rows = vItem/7; + NSInteger columns = vItem%7; + item = columns*6 + rows; + break; + } + case UICollectionViewScrollDirectionVertical: { + item = [self.gregorian components:NSCalendarUnitDay fromDate:head toDate:date options:0].day; + break; + } + } + break; + } + case FSCalendarScopeWeek: { + section = [self.gregorian components:NSCalendarUnitWeekOfYear fromDate:[self.gregorian fs_firstDayOfWeek:self.minimumDate] toDate:date options:0].weekOfYear; + item = (([self.gregorian component:NSCalendarUnitWeekday fromDate:date] - self.gregorian.firstWeekday) + 7) % 7; + break; + } + } + return [NSIndexPath indexPathForItem:item inSection:section]; +} + +- (NSIndexPath *)indexPathForDate:(NSDate *)date +{ + return [self indexPathForDate:date scope:self.calendar.scope]; +} + +- (void)reloadSections +{ + self.numberOfMonths = [self.gregorian components:NSCalendarUnitMonth fromDate:[self.gregorian fs_firstDayOfMonth:self.minimumDate] toDate:self.maximumDate options:0].month+1; + self.numberOfWeeks = [self.gregorian components:NSCalendarUnitWeekOfYear fromDate:[self.gregorian fs_firstDayOfWeek:self.minimumDate] toDate:self.maximumDate options:0].weekOfYear+1; + + [self.months removeAllObjects]; + [self.monthHeads removeAllObjects]; + [self.weeks removeAllObjects]; + + [self.rowNumbers removeAllObjects]; +} + +- (NSInteger)numberOfSections +{ + if (self.calendar.animator.transition == FSCalendarTransitionWeekToMonth) { + return self.numberOfMonths; + } else { + switch (self.calendar.scope) { + case FSCalendarScopeMonth: { + return self.numberOfMonths; + } + case FSCalendarScopeWeek: { + return self.numberOfWeeks; + } + } + } +} + +- (NSInteger)numberOfHeadPlaceholdersForMonth:(NSDate *)month +{ + NSInteger currentWeekday = [self.gregorian component:NSCalendarUnitWeekday fromDate:month]; + NSInteger number = ((currentWeekday- self.gregorian.firstWeekday) + 7) % 7 ?: (7 * (!self.calendar.floatingMode&&(self.calendar.placeholderType == FSCalendarPlaceholderTypeFillSixRows))); + return number; +} + +- (NSInteger)numberOfRowsInMonth:(NSDate *)month +{ + if (!month) return 0; + if (self.calendar.placeholderType == FSCalendarPlaceholderTypeFillSixRows) return 6; + + NSNumber *rowNumber = self.rowNumbers[month]; + if (!rowNumber) { + NSDate *firstDayOfMonth = [self.gregorian fs_firstDayOfMonth:month]; + NSInteger weekdayOfFirstDay = [self.gregorian component:NSCalendarUnitWeekday fromDate:firstDayOfMonth]; + NSInteger numberOfDaysInMonth = [self.gregorian fs_numberOfDaysInMonth:month]; + NSInteger numberOfPlaceholdersForPrev = ((weekdayOfFirstDay - self.gregorian.firstWeekday) + 7) % 7; + NSInteger headDayCount = numberOfDaysInMonth + numberOfPlaceholdersForPrev; + NSInteger numberOfRows = (headDayCount/7) + (headDayCount%7>0); + self.rowNumbers[month] = @(numberOfRows); + } + return rowNumber.integerValue; +} + +- (NSInteger)numberOfRowsInSection:(NSInteger)section +{ + if (self.calendar.scope == FSCalendarScopeWeek) return 1; + NSDate *month = [self monthForSection:section]; + return [self numberOfRowsInMonth:month]; +} + +#pragma mark - Private methods + +- (NSDate *)monthForSection:(NSInteger)section +{ + NSNumber *key = @(section); + NSDate *month = self.months[key]; + if (!month) { + month = [self.gregorian dateByAddingUnit:NSCalendarUnitMonth value:section toDate:[self.gregorian fs_firstDayOfMonth:self.minimumDate] options:0]; + NSInteger numberOfHeadPlaceholders = [self numberOfHeadPlaceholdersForMonth:month]; + NSDate *monthHead = [self.gregorian dateByAddingUnit:NSCalendarUnitDay value:-numberOfHeadPlaceholders toDate:month options:0]; + self.months[key] = month; + self.monthHeads[key] = monthHead; + } + return month; +} + +- (NSDate *)monthHeadForSection:(NSInteger)section +{ + NSNumber *key = @(section); + NSDate *monthHead = self.monthHeads[key]; + if (!monthHead) { + NSDate *month = [self.gregorian dateByAddingUnit:NSCalendarUnitMonth value:section toDate:[self.gregorian fs_firstDayOfMonth:self.minimumDate] options:0]; + NSInteger numberOfHeadPlaceholders = [self numberOfHeadPlaceholdersForMonth:month]; + monthHead = [self.gregorian dateByAddingUnit:NSCalendarUnitDay value:-numberOfHeadPlaceholders toDate:month options:0]; + self.months[key] = month; + self.monthHeads[key] = monthHead; + } + return monthHead; +} + +- (NSDate *)weekForSection:(NSInteger)section +{ + NSNumber *key = @(section); + NSDate *week = self.weeks[key]; + if (!week) { + week = [self.gregorian dateByAddingUnit:NSCalendarUnitWeekOfYear value:section toDate:[self.gregorian fs_firstDayOfWeek:self.minimumDate] options:0]; + self.weeks[key] = week; + } + return week; +} + +- (NSCalendar *)gregorian { return self.calendar.gregorian; } +- (NSDate *)minimumDate { return self.calendar.minimumDate; } +- (NSDate *)maximumDate { return self.calendar.maximumDate; } + +@end diff --git a/FSCalendar/FSCalendarCell.m b/FSCalendar/FSCalendarCell.m index 2bec89e..bb4e2de 100644 --- a/FSCalendar/FSCalendarCell.m +++ b/FSCalendar/FSCalendarCell.m @@ -153,7 +153,7 @@ NSIndexPath *indexPath = [self.calendar.collectionView indexPathForCell:self]; - NSInteger lineCount = [self.calendar numberOfRowsInMonth:self.month]; + NSInteger lineCount = [self.calendar.calculator numberOfRowsInMonth:self.month]; if (lineCount == 6) { self.contentView.hidden = NO; } else { @@ -187,8 +187,8 @@ if (_needsAdjustingViewFrame || CGSizeEqualToSize(_titleLabel.frame.size, CGSizeZero)) { _needsAdjustingViewFrame = NO; if (_subtitle) { - CGFloat titleHeight = [@"1" sizeWithAttributes:@{NSFontAttributeName:_titleLabel.font}].height; - CGFloat subtitleHeight = [@"1" sizeWithAttributes:@{NSFontAttributeName:_subtitleLabel.font}].height; + CGFloat titleHeight = self.calendar.calculator.titleHeight; + CGFloat subtitleHeight = self.calendar.calculator.subtitleHeight; CGFloat height = titleHeight + subtitleHeight; _titleLabel.frame = CGRectMake( diff --git a/FSCalendar/FSCalendarCollectionViewLayout.m b/FSCalendar/FSCalendarCollectionViewLayout.m index 1d98474..82f3b9a 100644 --- a/FSCalendar/FSCalendarCollectionViewLayout.m +++ b/FSCalendar/FSCalendarCollectionViewLayout.m @@ -12,7 +12,6 @@ #import "FSCalendarCollectionView.h" #import "FSCalendarExtensions.h" #import "FSCalendarConstants.h" -#import #define kFSCalendarSeparatorInterRows @"FSCalendarSeparatorInterRows" #define kFSCalendarSeparatorInterColumns @"FSCalendarSeparatorInterColumns" @@ -110,15 +109,16 @@ return NO; } - NSDate *currentPage = [self.calendar.gregorian dateByAddingUnit:NSCalendarUnitMonth value:evaluatedObject.indexPath.section toDate:[self.calendar.gregorian fs_firstDayOfMonth:self.calendar.minimumDate] options:0]; - NSInteger numberOfRows = [self.calendar numberOfRowsInMonth:currentPage]; + NSInteger numberOfRows = [self.calendar.calculator numberOfRowsInSection:evaluatedObject.indexPath.section]; switch (self.scrollDirection) { case UICollectionViewScrollDirectionHorizontal: { return evaluatedObject.indexPath.item < numberOfRows-1; } case UICollectionViewScrollDirectionVertical: { - return evaluatedObject.indexPath.item%7==0 && evaluatedObject.indexPath.item/7 *weekdays; @property (readonly, nonatomic) BOOL floatingMode; @property (readonly, nonatomic) NSArray *visibleStickyHeaders; @@ -57,13 +61,6 @@ - (BOOL)isPageInRange:(NSDate *)page; - (BOOL)isDateInRange:(NSDate *)date; -- (NSDate *)dateForIndexPath:(NSIndexPath *)indexPath; -- (NSDate *)dateForIndexPath:(NSIndexPath *)indexPath scope:(FSCalendarScope)scope; -- (NSIndexPath *)indexPathForDate:(NSDate *)date; -- (NSIndexPath *)indexPathForDate:(NSDate *)date scope:(FSCalendarScope)scope; - -- (NSInteger)numberOfHeadPlaceholdersForMonth:(NSDate *)month; -- (NSInteger)numberOfRowsInMonth:(NSDate *)month; - (CGSize)sizeThatFits:(CGSize)size scope:(FSCalendarScope)scope; diff --git a/FSCalendar/FSCalendarExtensions.h b/FSCalendar/FSCalendarExtensions.h index 2421a01..44d2d2c 100644 --- a/FSCalendar/FSCalendarExtensions.h +++ b/FSCalendar/FSCalendarExtensions.h @@ -48,6 +48,13 @@ NS_ASSUME_NONNULL_BEGIN @end +@interface NSCache (FSCalendarExtensions) + +- (void)setObject:(nullable id)obj forKeyedSubscript:(id)key; +- (id)objectForKeyedSubscript:(id)key; + +@end + @interface NSObject (FSCalendarExtensions) diff --git a/FSCalendar/FSCalendarExtensions.m b/FSCalendar/FSCalendarExtensions.m index 0a9cfc6..466a5b8 100644 --- a/FSCalendar/FSCalendarExtensions.m +++ b/FSCalendar/FSCalendarExtensions.m @@ -222,6 +222,26 @@ @end +@implementation NSCache (FSCalendarExtensions) + +- (void)setObject:(nullable id)obj forKeyedSubscript:(id)key +{ + if (!key) return; + + if (obj) { + [self setObject:obj forKey:key]; + } else { + [self removeObjectForKey:key]; + } +} + +- (id)objectForKeyedSubscript:(id)key +{ + return [self objectForKey:key]; +} + +@end + @implementation NSObject (FSCalendarExtensions) - (void)fs_setVariable:(id)variable forKey:(NSString *)key