548 lines
24 KiB
Objective-C
548 lines
24 KiB
Objective-C
//
|
|
// FSCalendarAnimationLayout.m
|
|
// FSCalendar
|
|
//
|
|
// Created by dingwenchao on 1/3/16.
|
|
// Copyright © 2016 Wenchao Ding. All rights reserved.
|
|
//
|
|
|
|
#import "FSCalendarCollectionViewLayout.h"
|
|
#import "FSCalendar.h"
|
|
#import "FSCalendarDynamicHeader.h"
|
|
#import "FSCalendarCollectionView.h"
|
|
#import "FSCalendarExtensions.h"
|
|
#import "FSCalendarConstants.h"
|
|
|
|
#define kFSCalendarSeparatorInterRows @"FSCalendarSeparatorInterRows"
|
|
#define kFSCalendarSeparatorInterColumns @"FSCalendarSeparatorInterColumns"
|
|
|
|
@interface FSCalendarCollectionViewLayout ()
|
|
|
|
@property (assign, nonatomic) CGFloat *widths;
|
|
@property (assign, nonatomic) CGFloat *heights;
|
|
@property (assign, nonatomic) CGFloat *lefts;
|
|
@property (assign, nonatomic) CGFloat *tops;
|
|
@property (assign, nonatomic) CGFloat *sectionHeights;
|
|
@property (assign, nonatomic) CGFloat *sectionTops;
|
|
@property (assign, nonatomic) CGFloat *sectionBottoms;
|
|
@property (assign, nonatomic) CGFloat *sectionRowCounts;
|
|
|
|
@property (assign, nonatomic) CGSize estimatedItemSize;
|
|
|
|
@property (assign, nonatomic) CGSize contentSize;
|
|
@property (assign, nonatomic) CGSize collectionViewSize;
|
|
@property (assign, nonatomic) NSInteger numberOfSections;
|
|
|
|
@property (strong, nonatomic) NSMutableDictionary<NSIndexPath *, UICollectionViewLayoutAttributes *> *itemAttributes;
|
|
@property (strong, nonatomic) NSMutableDictionary<NSIndexPath *, UICollectionViewLayoutAttributes *> *headerAttributes;
|
|
@property (strong, nonatomic) NSMutableDictionary<NSIndexPath *, UICollectionViewLayoutAttributes *> *rowSeparatorAttributes;
|
|
|
|
- (void)didReceiveNotifications:(NSNotification *)notification;
|
|
|
|
@end
|
|
|
|
@implementation FSCalendarCollectionViewLayout
|
|
|
|
- (instancetype)init
|
|
{
|
|
self = [super init];
|
|
if (self) {
|
|
self.estimatedItemSize = CGSizeZero;
|
|
self.widths = NULL;
|
|
self.heights = NULL;
|
|
self.tops = NULL;
|
|
self.lefts = NULL;
|
|
|
|
self.sectionHeights = NULL;
|
|
self.sectionTops = NULL;
|
|
self.sectionBottoms = NULL;
|
|
self.sectionRowCounts = NULL;
|
|
|
|
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
|
self.sectionInsets = UIEdgeInsetsMake(5, 0, 5, 0);
|
|
|
|
self.itemAttributes = [NSMutableDictionary dictionary];
|
|
self.headerAttributes = [NSMutableDictionary dictionary];
|
|
self.rowSeparatorAttributes = [NSMutableDictionary dictionary];
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveNotifications:) name:UIDeviceOrientationDidChangeNotification object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveNotifications:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
|
|
|
[self registerClass:[FSCalendarSeparator class] forDecorationViewOfKind:kFSCalendarSeparatorInterRows];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
|
|
|
|
free(self.widths);
|
|
free(self.heights);
|
|
free(self.tops);
|
|
free(self.lefts);
|
|
|
|
free(self.sectionHeights);
|
|
free(self.sectionTops);
|
|
free(self.sectionRowCounts);
|
|
free(self.sectionBottoms);
|
|
}
|
|
|
|
- (void)prepareLayout
|
|
{
|
|
if (CGSizeEqualToSize(self.collectionViewSize, self.collectionView.frame.size) && self.numberOfSections == self.collectionView.numberOfSections) {
|
|
return;
|
|
}
|
|
self.collectionViewSize = self.collectionView.frame.size;
|
|
[self.itemAttributes removeAllObjects];
|
|
[self.headerAttributes removeAllObjects];
|
|
[self.rowSeparatorAttributes removeAllObjects];
|
|
|
|
self.headerReferenceSize = ({
|
|
CGSize headerSize = CGSizeZero;
|
|
if (self.calendar.floatingMode) {
|
|
CGFloat headerHeight = self.calendar.preferredWeekdayHeight*1.5+self.calendar.preferredHeaderHeight;
|
|
headerSize = CGSizeMake(self.collectionView.fs_width, headerHeight);
|
|
}
|
|
headerSize;
|
|
});
|
|
self.estimatedItemSize = ({
|
|
CGFloat width = (self.collectionView.fs_width-self.sectionInsets.left-self.sectionInsets.right)/7.0;
|
|
CGFloat height = ({
|
|
CGFloat height = FSCalendarStandardRowHeight;
|
|
if (!self.calendar.floatingMode) {
|
|
switch (self.calendar.transitionCoordinator.representingScope) {
|
|
case FSCalendarScopeMonth: {
|
|
height = (self.collectionView.fs_height-self.sectionInsets.top-self.sectionInsets.bottom)/6.0;
|
|
break;
|
|
}
|
|
case FSCalendarScopeWeek: {
|
|
height = (self.collectionView.fs_height-self.sectionInsets.top-self.sectionInsets.bottom);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
height;
|
|
});
|
|
CGSize size = CGSizeMake(width, height);
|
|
size;
|
|
});
|
|
|
|
// Calculate item widths and lefts
|
|
free(self.widths);
|
|
self.widths = ({
|
|
NSInteger columnCount = 7;
|
|
size_t columnSize = sizeof(CGFloat)*columnCount;
|
|
CGFloat *widths = malloc(columnSize);
|
|
CGFloat contentWidth = self.collectionView.fs_width - self.sectionInsets.left - self.sectionInsets.right;
|
|
for (int i = 0; i < columnCount; i++) {
|
|
NSInteger currentCount = columnCount-i;
|
|
CGFloat actualWidth = FSCalendarRound(contentWidth/currentCount*2)*0.5;
|
|
contentWidth -= actualWidth;
|
|
widths[i] = actualWidth;
|
|
}
|
|
widths;
|
|
});
|
|
|
|
free(self.lefts);
|
|
self.lefts = ({
|
|
NSInteger columnCount = 7;
|
|
size_t columnSize = sizeof(CGFloat)*columnCount;
|
|
CGFloat *lefts = malloc(columnSize);
|
|
lefts[0] = self.sectionInsets.left;
|
|
for (int i = 1; i < columnCount; i++) {
|
|
lefts[i] = lefts[i-1] + self.widths[i-1];
|
|
}
|
|
lefts;
|
|
});
|
|
|
|
// Calculate item heights and tops
|
|
free(self.heights);
|
|
self.heights = ({
|
|
NSInteger rowCount = self.calendar.transitionCoordinator.representingScope == FSCalendarScopeWeek ? 1 : 6;
|
|
size_t rowSize = sizeof(CGFloat)*rowCount;
|
|
CGFloat *heights = malloc(rowSize);
|
|
if (!self.calendar.floatingMode) {
|
|
CGFloat contentHeight = self.collectionView.fs_height - self.sectionInsets.top - self.sectionInsets.bottom;
|
|
for (int i = 0; i < rowCount; i++) {
|
|
NSInteger currentCount = rowCount-i;
|
|
CGFloat actualHeight = FSCalendarRound(contentHeight/currentCount*2)*0.5;
|
|
contentHeight -= actualHeight;
|
|
heights[i] = actualHeight;
|
|
}
|
|
} else {
|
|
for (int i = 0; i < rowCount; i++) {
|
|
heights[i] = self.estimatedItemSize.height;
|
|
}
|
|
}
|
|
heights;
|
|
});
|
|
free(self.tops);
|
|
self.tops = ({
|
|
NSInteger rowCount = self.calendar.transitionCoordinator.representingScope == FSCalendarScopeWeek ? 1 : 6;
|
|
size_t rowSize = sizeof(CGFloat)*rowCount;
|
|
CGFloat *tops = malloc(rowSize);
|
|
tops[0] = self.sectionInsets.top;
|
|
for (int i = 1; i < rowCount; i++) {
|
|
tops[i] = tops[i-1] + self.heights[i-1];
|
|
}
|
|
tops;
|
|
});
|
|
|
|
// Calculate content size
|
|
self.numberOfSections = self.collectionView.numberOfSections;
|
|
self.contentSize = ({
|
|
CGSize contentSize = CGSizeZero;
|
|
if (!self.calendar.floatingMode) {
|
|
CGFloat width = self.collectionView.fs_width;
|
|
CGFloat height = self.collectionView.fs_height;
|
|
switch (self.scrollDirection) {
|
|
case UICollectionViewScrollDirectionHorizontal: {
|
|
width *= self.numberOfSections;
|
|
break;
|
|
}
|
|
case UICollectionViewScrollDirectionVertical: {
|
|
height *= self.numberOfSections;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
contentSize = CGSizeMake(width, height);
|
|
} else {
|
|
free(self.sectionHeights);
|
|
self.sectionHeights = malloc(sizeof(CGFloat)*self.numberOfSections);
|
|
free(self.sectionRowCounts);
|
|
self.sectionRowCounts = malloc(sizeof(NSInteger)*self.numberOfSections);
|
|
CGFloat width = self.collectionView.fs_width;
|
|
CGFloat height = 0;
|
|
for (int i = 0; i < self.numberOfSections; i++) {
|
|
NSInteger rowCount = [self.calendar.calculator numberOfRowsInSection:i];
|
|
self.sectionRowCounts[i] = rowCount;
|
|
CGFloat sectionHeight = self.headerReferenceSize.height;
|
|
for (int j = 0; j < rowCount; j++) {
|
|
sectionHeight += self.heights[j];
|
|
}
|
|
self.sectionHeights[i] = sectionHeight;
|
|
height += sectionHeight;
|
|
}
|
|
free(self.sectionTops);
|
|
self.sectionTops = malloc(sizeof(CGFloat)*self.numberOfSections);
|
|
free(self.sectionBottoms);
|
|
self.sectionBottoms = malloc(sizeof(CGFloat)*self.numberOfSections);
|
|
self.sectionTops[0] = 0;
|
|
self.sectionBottoms[0] = self.sectionHeights[0];
|
|
for (int i = 1; i < self.numberOfSections; i++) {
|
|
self.sectionTops[i] = self.sectionTops[i-1] + self.sectionHeights[i-1];
|
|
self.sectionBottoms[i] = self.sectionTops[i] + self.sectionHeights[i];
|
|
}
|
|
contentSize = CGSizeMake(width, height);
|
|
}
|
|
contentSize;
|
|
});
|
|
|
|
}
|
|
|
|
- (CGSize)collectionViewContentSize
|
|
{
|
|
return self.contentSize;
|
|
}
|
|
|
|
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
|
|
{
|
|
// Clipping
|
|
rect = CGRectIntersection(rect, CGRectMake(0, 0, self.contentSize.width, self.contentSize.height));
|
|
if (CGRectIsEmpty(rect)) return nil;
|
|
|
|
// Calculating attributes
|
|
NSMutableArray<UICollectionViewLayoutAttributes *> *layoutAttributes = [NSMutableArray array];
|
|
|
|
if (!self.calendar.floatingMode) {
|
|
|
|
switch (self.scrollDirection) {
|
|
case UICollectionViewScrollDirectionHorizontal: {
|
|
|
|
NSInteger wholeSections = rect.size.width/self.collectionView.fs_width;
|
|
NSInteger numberOfColumns = wholeSections*7;
|
|
NSInteger numberOfRows = self.calendar.transitionCoordinator.representingScope == FSCalendarScopeMonth ? 6 : 1;
|
|
|
|
NSInteger startSection = rect.origin.x/self.collectionView.fs_width;
|
|
CGFloat widthDelta1 = FSCalendarMod(CGRectGetMinX(rect), self.collectionView.fs_width) - self.sectionInsets.left;
|
|
widthDelta1 = MAX(0, widthDelta1);
|
|
NSInteger columnCountDelta1 = FSCalendarFloor(widthDelta1/self.estimatedItemSize.width);
|
|
numberOfColumns += (7-columnCountDelta1) % 7;
|
|
NSInteger startColumn = startSection*7 + columnCountDelta1%7;
|
|
|
|
CGFloat widthDelta2 = FSCalendarMod(CGRectGetMaxX(rect), self.collectionView.fs_width - self.sectionInsets.left);
|
|
widthDelta2 = MAX(0, widthDelta2);
|
|
|
|
NSInteger columnCountDelta2 = FSCalendarCeil(widthDelta2/self.estimatedItemSize.width);
|
|
numberOfColumns += columnCountDelta2%7;
|
|
|
|
NSInteger endColumn = startColumn + numberOfColumns - 1;
|
|
|
|
for (NSInteger column = startColumn; column <= endColumn; column++) {
|
|
for (NSInteger row = 0; row < numberOfRows; row++) {
|
|
NSInteger section = column / 7;
|
|
NSInteger item = column % 7 + row * 7;
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:section];
|
|
UICollectionViewLayoutAttributes *itemAttributes = [self layoutAttributesForItemAtIndexPath:indexPath];
|
|
[layoutAttributes addObject:itemAttributes];
|
|
|
|
UICollectionViewLayoutAttributes *rowSeparatorAttributes = [self layoutAttributesForDecorationViewOfKind:kFSCalendarSeparatorInterRows atIndexPath:indexPath];
|
|
if (rowSeparatorAttributes) {
|
|
[layoutAttributes addObject:rowSeparatorAttributes];
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case UICollectionViewScrollDirectionVertical: {
|
|
|
|
NSInteger wholeSections = rect.size.height/self.collectionView.fs_height;
|
|
NSInteger numberOfRows = wholeSections*6;
|
|
|
|
NSInteger startSection = rect.origin.y/self.collectionView.fs_height;
|
|
CGFloat heightDelta1 = FSCalendarMod(CGRectGetMinY(rect), self.collectionView.fs_height)-self.sectionInsets.top;
|
|
heightDelta1 = MAX(0, heightDelta1);
|
|
NSInteger rowCountDelta1 = FSCalendarFloor(heightDelta1/self.estimatedItemSize.height);
|
|
numberOfRows += (6-rowCountDelta1) % 6;
|
|
NSInteger startRow = startSection*6 + rowCountDelta1%6;
|
|
|
|
CGFloat heightDelta2 = FSCalendarMod(CGRectGetMaxY(rect), self.collectionView.fs_height);
|
|
heightDelta2 = MAX(0, heightDelta2-self.sectionInsets.bottom);
|
|
|
|
NSInteger rowCountDelta2 = FSCalendarCeil(heightDelta2/self.estimatedItemSize.height);
|
|
numberOfRows += rowCountDelta2;
|
|
|
|
NSInteger endRow = startRow + numberOfRows - 1;
|
|
|
|
for (NSInteger row = startRow; row <= endRow; row++) {
|
|
for (NSInteger column = 0; column < 7; column++) {
|
|
NSInteger section = row / 6;
|
|
NSInteger item = column + (row % 6) * 7;
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:section];
|
|
UICollectionViewLayoutAttributes *itemAttributes = [self layoutAttributesForItemAtIndexPath:indexPath];
|
|
[layoutAttributes addObject:itemAttributes];
|
|
|
|
UICollectionViewLayoutAttributes *rowSeparatorAttributes = [self layoutAttributesForDecorationViewOfKind:kFSCalendarSeparatorInterRows atIndexPath:indexPath];
|
|
if (rowSeparatorAttributes) {
|
|
[layoutAttributes addObject:rowSeparatorAttributes];
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
|
|
NSInteger startSection = [self searchStartSection:rect :0 :self.numberOfSections-1];
|
|
NSInteger startRowIndex = ({
|
|
CGFloat heightDelta1 = MIN(self.sectionBottoms[startSection]-CGRectGetMinY(rect)-self.sectionInsets.bottom, self.sectionRowCounts[startSection]*self.estimatedItemSize.height);
|
|
NSInteger startRowCount = FSCalendarCeil(heightDelta1/self.estimatedItemSize.height);
|
|
NSInteger startRowIndex = self.sectionRowCounts[startSection]-startRowCount;
|
|
startRowIndex;
|
|
});
|
|
|
|
NSInteger endSection = [self searchEndSection:rect :startSection :self.numberOfSections-1];
|
|
NSInteger endRowIndex = ({
|
|
CGFloat heightDelta2 = MAX(CGRectGetMaxY(rect) - self.sectionTops[endSection]- self.headerReferenceSize.height - self.sectionInsets.top, 0);
|
|
NSInteger endRowCount = FSCalendarCeil(heightDelta2/self.estimatedItemSize.height);
|
|
NSInteger endRowIndex = endRowCount - 1;
|
|
endRowIndex;
|
|
});
|
|
for (NSInteger section = startSection; section <= endSection; section++) {
|
|
NSInteger startRow = (section == startSection) ? startRowIndex : 0;
|
|
NSInteger endRow = (section == endSection) ? endRowIndex : self.sectionRowCounts[section]-1;
|
|
UICollectionViewLayoutAttributes *headerAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
|
|
[layoutAttributes addObject:headerAttributes];
|
|
for (NSInteger row = startRow; row <= endRow; row++) {
|
|
for (NSInteger column = 0; column < 7; column++) {
|
|
NSInteger item = row * 7 + column;
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:section];
|
|
UICollectionViewLayoutAttributes *itemAttributes = [self layoutAttributesForItemAtIndexPath:indexPath];
|
|
[layoutAttributes addObject:itemAttributes];
|
|
UICollectionViewLayoutAttributes *rowSeparatorAttributes = [self layoutAttributesForDecorationViewOfKind:kFSCalendarSeparatorInterRows atIndexPath:indexPath];
|
|
if (rowSeparatorAttributes) {
|
|
[layoutAttributes addObject:rowSeparatorAttributes];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
return [NSArray arrayWithArray:layoutAttributes];
|
|
|
|
}
|
|
|
|
// Items
|
|
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
FSCalendarCoordinate coordinate = [self.calendar.calculator coordinateForIndexPath:indexPath];
|
|
NSInteger column = coordinate.column;
|
|
NSInteger row = coordinate.row;
|
|
UICollectionViewLayoutAttributes *attributes = self.itemAttributes[indexPath];
|
|
if (!attributes) {
|
|
attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
|
|
CGRect frame = ({
|
|
CGFloat x, y;
|
|
switch (self.scrollDirection) {
|
|
case UICollectionViewScrollDirectionHorizontal: {
|
|
x = self.lefts[column] + indexPath.section * self.collectionView.fs_width;
|
|
y = self.tops[row];
|
|
break;
|
|
}
|
|
case UICollectionViewScrollDirectionVertical: {
|
|
x = self.lefts[column];
|
|
if (!self.calendar.floatingMode) {
|
|
y = self.tops[row] + indexPath.section * self.collectionView.fs_height;
|
|
} else {
|
|
y = self.sectionTops[indexPath.section] + self.headerReferenceSize.height + self.tops[row];
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
CGFloat width = self.widths[column];
|
|
CGFloat height = self.heights[row];
|
|
CGRect frame = CGRectMake(x, y, width, height);
|
|
frame;
|
|
});
|
|
attributes.frame = frame;
|
|
self.itemAttributes[indexPath] = attributes;
|
|
}
|
|
return attributes;
|
|
}
|
|
|
|
// Section headers
|
|
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
if ([elementKind isEqualToString:UICollectionElementKindSectionHeader]) {
|
|
UICollectionViewLayoutAttributes *attributes = self.headerAttributes[indexPath];
|
|
if (!attributes) {
|
|
attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader withIndexPath:indexPath];
|
|
attributes.frame = CGRectMake(0, self.sectionTops[indexPath.section], self.collectionView.fs_width, self.headerReferenceSize.height);
|
|
self.headerAttributes[indexPath] = attributes;
|
|
}
|
|
return attributes;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
// Separators
|
|
- (UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
if ([elementKind isEqualToString:kFSCalendarSeparatorInterRows] && (self.calendar.appearance.separators & FSCalendarSeparatorInterRows)) {
|
|
UICollectionViewLayoutAttributes *attributes = self.rowSeparatorAttributes[indexPath];
|
|
if (!attributes) {
|
|
FSCalendarCoordinate coordinate = [self.calendar.calculator coordinateForIndexPath:indexPath];
|
|
if (coordinate.row >= [self.calendar.calculator numberOfRowsInSection:indexPath.section]-1) {
|
|
return nil;
|
|
}
|
|
attributes = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:kFSCalendarSeparatorInterRows withIndexPath:indexPath];
|
|
CGFloat x, y;
|
|
|
|
if (!self.calendar.floatingMode) {
|
|
switch (self.scrollDirection) {
|
|
case UICollectionViewScrollDirectionHorizontal: {
|
|
x = self.lefts[coordinate.column];
|
|
y = self.tops[coordinate.row]+self.heights[coordinate.row];
|
|
break;
|
|
}
|
|
case UICollectionViewScrollDirectionVertical: {
|
|
x = 0;
|
|
y = self.tops[coordinate.row]+self.heights[coordinate.row] + indexPath.section * self.collectionView.fs_height;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
x = 0;
|
|
y = self.sectionTops[indexPath.section] + self.headerReferenceSize.height + self.tops[coordinate.row] + self.heights[coordinate.row];
|
|
}
|
|
CGFloat width = self.collectionView.fs_width;
|
|
CGFloat height = FSCalendarStandardSeparatorThickness;
|
|
attributes.frame = CGRectMake(x, y, width, height);
|
|
attributes.zIndex = NSIntegerMax;
|
|
self.rowSeparatorAttributes[indexPath] = attributes;
|
|
}
|
|
return attributes;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
#pragma mark - Notifications
|
|
|
|
- (void)didReceiveNotifications:(NSNotification *)notification
|
|
{
|
|
if ([notification.name isEqualToString:UIDeviceOrientationDidChangeNotification]) {
|
|
[self invalidateLayout];
|
|
}
|
|
if ([notification.name isEqualToString:UIApplicationDidReceiveMemoryWarningNotification]) {
|
|
[self.itemAttributes removeAllObjects];
|
|
[self.headerAttributes removeAllObjects];
|
|
[self.rowSeparatorAttributes removeAllObjects];
|
|
}
|
|
}
|
|
|
|
#pragma mark - Private properties
|
|
|
|
- (void)setScrollDirection:(UICollectionViewScrollDirection)scrollDirection
|
|
{
|
|
if (_scrollDirection != scrollDirection) {
|
|
_scrollDirection = scrollDirection;
|
|
self.collectionViewSize = CGSizeAutomatic;
|
|
}
|
|
}
|
|
|
|
#pragma mark - Private functions
|
|
|
|
- (NSInteger)searchStartSection:(CGRect)rect :(NSInteger)left :(NSInteger)right
|
|
{
|
|
NSInteger mid = left + (right-left)/2;
|
|
CGFloat y = rect.origin.y;
|
|
CGFloat minY = self.sectionTops[mid];
|
|
CGFloat maxY = self.sectionBottoms[mid];
|
|
if (y >= minY && y < maxY) {
|
|
return mid;
|
|
} else if (y < minY) {
|
|
return [self searchStartSection:rect :left :mid];
|
|
} else {
|
|
return [self searchStartSection:rect :mid+1 :right];
|
|
}
|
|
}
|
|
|
|
- (NSInteger)searchEndSection:(CGRect)rect :(NSInteger)left :(NSInteger)right
|
|
{
|
|
NSInteger mid = left + (right-left)/2;
|
|
CGFloat y = CGRectGetMaxY(rect);
|
|
CGFloat minY = self.sectionTops[mid];
|
|
CGFloat maxY = self.sectionBottoms[mid];
|
|
if (y > minY && y <= maxY) {
|
|
return mid;
|
|
} else if (y <= minY) {
|
|
return [self searchEndSection:rect :left :mid];
|
|
} else {
|
|
return [self searchEndSection:rect :mid+1 :right];
|
|
}
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
#undef kFSCalendarSeparatorInterColumns
|
|
#undef kFSCalendarSeparatorInterRows
|
|
|
|
|