Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge

  • Loading branch information...
commit 3e0ca0372e5651b95d4e49481c998aed8c21b6a7 2 parents f0bd6d1 + 1a0059a
Zach Drayer authored
View
2  Examples/GridViewDemo/GridViewDemo/GridViewDemoViewController.m
@@ -168,7 +168,7 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
-- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
+- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
CATransition *fadeTransition = [CATransition animation];
fadeTransition.duration = duration;
View
16 KKGridView.xcodeproj/project.pbxproj
@@ -29,8 +29,8 @@
F42166A714A3A610004E0C32 /* KKGridViewIndexView.m in Sources */ = {isa = PBXBuildFile; fileRef = F42166A514A3A610004E0C32 /* KKGridViewIndexView.m */; };
FC368B40149B483900B92E57 /* KKBlocksDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = FC368B3E149B483900B92E57 /* KKBlocksDelegate.h */; };
FC368B41149B483900B92E57 /* KKBlocksDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FC368B3F149B483900B92E57 /* KKBlocksDelegate.m */; };
- FC53DF8313E629FE000767B1 /* KKGridViewViewInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = FC53DF8113E629FE000767B1 /* KKGridViewViewInfo.h */; };
- FC53DF8413E629FE000767B1 /* KKGridViewViewInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = FC53DF8213E629FE000767B1 /* KKGridViewViewInfo.m */; };
+ FC53DF8313E629FE000767B1 /* KKGridViewSectionInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = FC53DF8113E629FE000767B1 /* KKGridViewSectionInfo.h */; };
+ FC53DF8413E629FE000767B1 /* KKGridViewSectionInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = FC53DF8213E629FE000767B1 /* KKGridViewSectionInfo.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -61,8 +61,8 @@
F42166A514A3A610004E0C32 /* KKGridViewIndexView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KKGridViewIndexView.m; sourceTree = "<group>"; };
FC368B3E149B483900B92E57 /* KKBlocksDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KKBlocksDelegate.h; sourceTree = "<group>"; };
FC368B3F149B483900B92E57 /* KKBlocksDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KKBlocksDelegate.m; sourceTree = "<group>"; };
- FC53DF8113E629FE000767B1 /* KKGridViewViewInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KKGridViewViewInfo.h; sourceTree = "<group>"; };
- FC53DF8213E629FE000767B1 /* KKGridViewViewInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KKGridViewViewInfo.m; sourceTree = "<group>"; };
+ FC53DF8113E629FE000767B1 /* KKGridViewSectionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KKGridViewSectionInfo.h; sourceTree = "<group>"; };
+ FC53DF8213E629FE000767B1 /* KKGridViewSectionInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KKGridViewSectionInfo.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -126,8 +126,8 @@
1A3F1B7313E34CF8006747A3 /* KKGridViewUpdate.m */,
1A3F1B6E13E34A61006747A3 /* KKGridViewUpdateStack.h */,
1A3F1B6F13E34A61006747A3 /* KKGridViewUpdateStack.m */,
- FC53DF8113E629FE000767B1 /* KKGridViewViewInfo.h */,
- FC53DF8213E629FE000767B1 /* KKGridViewViewInfo.m */,
+ FC53DF8113E629FE000767B1 /* KKGridViewSectionInfo.h */,
+ FC53DF8213E629FE000767B1 /* KKGridViewSectionInfo.m */,
1A0BEC7413DDF862003C2632 /* KKIndexPath.h */,
1A0BEC7513DDF862003C2632 /* KKIndexPath.m */,
1A72A9731453AE42002546F8 /* KKGridViewController.h */,
@@ -180,7 +180,7 @@
1A0BEC7613DDF862003C2632 /* KKIndexPath.h in Headers */,
1A3F1B7413E34CF8006747A3 /* KKGridViewUpdate.h in Headers */,
1A3F1B7013E34A62006747A3 /* KKGridViewUpdateStack.h in Headers */,
- FC53DF8313E629FE000767B1 /* KKGridViewViewInfo.h in Headers */,
+ FC53DF8313E629FE000767B1 /* KKGridViewSectionInfo.h in Headers */,
FC368B40149B483900B92E57 /* KKBlocksDelegate.h in Headers */,
F42166A614A3A610004E0C32 /* KKGridViewIndexView.h in Headers */,
);
@@ -242,7 +242,7 @@
1A0BEC7713DDF862003C2632 /* KKIndexPath.m in Sources */,
1A3F1B7113E34A62006747A3 /* KKGridViewUpdateStack.m in Sources */,
1A3F1B7513E34CF8006747A3 /* KKGridViewUpdate.m in Sources */,
- FC53DF8413E629FE000767B1 /* KKGridViewViewInfo.m in Sources */,
+ FC53DF8413E629FE000767B1 /* KKGridViewSectionInfo.m in Sources */,
1A72A9761453AE42002546F8 /* KKGridViewController.m in Sources */,
FC368B41149B483900B92E57 /* KKBlocksDelegate.m in Sources */,
F42166A714A3A610004E0C32 /* KKGridViewIndexView.m in Sources */,
View
8 KKGridView/Definitions.h
@@ -15,9 +15,11 @@
// Macros
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000
-#define __kk_weak weak
-#else
-#define __kk_weak unsafe_unretained
+#define kk_weak weak
+#define __kk_weak __weak
+#else
+#define kk_weak unsafe_unretained
+#define __kk_weak __unsafe_unretained
#endif
static inline bool KKCGRectIntersectsRectVertically(CGRect rect1, CGRect rect2)
View
4 KKGridView/KKGridView.h
@@ -46,8 +46,8 @@ typedef enum {
@property (nonatomic, readonly) NSUInteger numberOfSections;
#pragma mark - Data Source and Delegate
-@property (nonatomic, __kk_weak) IBOutlet id <KKGridViewDataSource> dataSource;
-@property (nonatomic, __kk_weak) IBOutlet id <KKGridViewDelegate> gridDelegate;
+@property (nonatomic, kk_weak) IBOutlet id <KKGridViewDataSource> dataSource;
+@property (nonatomic, kk_weak) IBOutlet id <KKGridViewDelegate> gridDelegate;
#pragma mark - Getters
View
261 KKGridView/KKGridView.m
@@ -7,7 +7,7 @@
//
#import <KKGridView/KKGridView.h>
-#import <KKGridView/KKGridViewViewInfo.h>
+#import <KKGridView/KKGridViewSectionInfo.h>
#import <KKGridView/KKIndexPath.h>
#import <KKGridView/KKGridViewUpdate.h>
#import <KKGridView/KKGridViewUpdateStack.h>
@@ -88,12 +88,12 @@ - (void)_respondToBoundsChange;
// Internal Layout
- (void)_cleanupCells;
-- (void)_layoutAccessories;
+- (void)_layoutSectionViews;
- (void)_layoutExtremities;
- (void)_layoutGridView; /* Only call this directly; prefer -setNeedsLayout */
- (void)_layoutVisibleCells;
- (void)_layoutModelCells;
-- (void)_configureAuxiliaryView:(KKGridViewViewInfo *)headerOrFooter inSection:(NSUInteger)section withStickPoint:(CGFloat)stickPoint height:(CGFloat)height;
+- (void)_configureSectionView:(KKGridViewSectionInfo *)headerOrFooter inSection:(NSUInteger)section withStickPoint:(CGFloat)stickPoint height:(CGFloat)height;
- (void)_performRemainingUpdatesModelOnly;
// Metrics
@@ -124,6 +124,9 @@ - (UIView *)_viewForFooterInSection:(NSUInteger)section;
// Custom Subviewinsertion
- (void)_insertSubviewBelowScrollbar:(UIView *)view;
+
+// Animation Helpers
++ (void)animateIf:(BOOL)animated delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options block:(void(^)())block;
@end
@implementation KKGridView
@@ -144,11 +147,7 @@ @implementation KKGridView
- (id)init
{
- if ((self = [super init])) {
- [self _sharedInitialization];
- }
-
- return self;
+ return [self initWithFrame:CGRectZero];
}
- (id)initWithCoder:(NSCoder *)aDecoder
@@ -276,7 +275,7 @@ - (void)setAllowsMultipleSelection:(BOOL)allowsMultipleSelection
{
if (!allowsMultipleSelection && _allowsMultipleSelection == YES) {
[_selectedIndexPaths removeAllObjects];
- [UIView animateWithDuration:KKGridViewDefaultAnimationDuration delay:0 options:(UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionBeginFromCurrentState) animations:^(void) {
+ [UIView animateWithDuration:KKGridViewDefaultAnimationDuration delay:0 options:(UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionBeginFromCurrentState) animations:^{
[self _layoutGridView];
} completion:nil];
}
@@ -343,7 +342,7 @@ - (void)layoutSubviews
- (void)_layoutGridView
{
[self _layoutVisibleCells];
- [self _layoutAccessories];
+ [self _layoutSectionViews];
[self _layoutExtremities];
_markedForDisplay = NO;
_staggerForInsertion = NO;
@@ -352,7 +351,7 @@ - (void)_layoutGridView
#pragma mark - Private Layout Methods
-- (void)_layoutAccessories
+- (void)_layoutSectionViews
{
CGRect visibleBounds = CGRectMake(self.contentOffset.x + self.contentInset.left, self.contentOffset.y + self.contentInset.top, self.bounds.size.width - self.contentInset.right, self.bounds.size.height - self.contentInset.bottom);
@@ -489,26 +488,16 @@ - (void)_layoutVisibleCells
NSMutableSet *replacementSet = [[NSMutableSet alloc] initWithCapacity:[_selectedIndexPaths count]];
for (KKIndexPath *keyPath in _selectedIndexPaths) {
-
- void (^addCorrectKeyPath)(BOOL) = ^(BOOL condition) {
- NSInteger delta = KKGridViewUpdateIsNegative[update.type] ? -1 : 1;
- if (indexPath.section == keyPath.section && condition) {
- [replacementSet addObject:[KKIndexPath indexPathForIndex:keyPath.index + delta inSection:keyPath.section]];
- } else {
- [replacementSet addObject:keyPath];
- }
+ BOOL conditionMap[KKGridViewUpdateTypeSectionReload+1] = {
+ [KKGridViewUpdateTypeItemInsert] = keyPath.index >= indexPath.index,
+ [KKGridViewUpdateTypeItemDelete] = indexPath.index < keyPath.index && keyPath.index != 0
};
- switch (update.type) {
- case KKGridViewUpdateTypeItemInsert:
- addCorrectKeyPath(keyPath.index >= indexPath.index);
- break;
- case KKGridViewUpdateTypeItemDelete:
- addCorrectKeyPath(indexPath.index < keyPath.index && keyPath.index != 0);
- break;
- default:
- [replacementSet addObject:keyPath];
- break;
+ NSInteger delta = KKGridViewUpdateIsNegative[update.type] ? -1 : 1;
+ if (conditionMap[update.type] && indexPath.section == keyPath.section) {
+ [replacementSet addObject:[KKIndexPath indexPathForIndex:keyPath.index + delta inSection:keyPath.section]];
+ } else {
+ [replacementSet addObject:keyPath];
}
}
@@ -523,15 +512,9 @@ - (void)_layoutVisibleCells
KKGridViewCell *cell = [_visibleCells objectForKey:keyPath];
cell.selected = [_selectedIndexPaths containsObject:keyPath];
- if (_staggerForInsertion) {
- [UIView animateWithDuration:KKGridViewDefaultAnimationDuration
- delay:0.0015
- options:UIViewAnimationOptionCurveEaseInOut
- animations:^{ updateCellFrame(cell,indexPath); }
- completion:nil];
- } else {
+ [KKGridView animateIf:_staggerForInsertion delay:0.0015 options:UIViewAnimationOptionCurveEaseInOut block:^{
updateCellFrame(cell,indexPath);
- }
+ }];
}
}
}
@@ -541,16 +524,10 @@ - (void)_layoutVisibleCells
[self _displayCell:cell atIndexPath:indexPath withAnimation:animation];
}
- else if (_markedForDisplay) {
- if (_staggerForInsertion) {
- [UIView animateWithDuration:KKGridViewDefaultAnimationDuration
- delay:(index + 1) * 0.0015
- options:UIViewAnimationOptionBeginFromCurrentState
- animations:^{ updateCellFrame(cell, indexPath); }
- completion:nil];
- } else {
+ else if (_markedForDisplay) {
+ [KKGridView animateIf:_staggerForInsertion delay:(index + 1) * 0.0015 options:UIViewAnimationOptionBeginFromCurrentState block:^{
updateCellFrame(cell, indexPath);
- }
+ }];
}
cell.selected = [_selectedIndexPaths containsObject:indexPath];
@@ -560,7 +537,7 @@ - (void)_layoutVisibleCells
[self _cleanupCells];
if (_needsAccessoryReload) {
- [UIView animateWithDuration:KKGridViewDefaultAnimationDuration delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void) {
+ [UIView animateWithDuration:KKGridViewDefaultAnimationDuration delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
[self reloadContentSize];
for (NSUInteger section = 0; section < _metrics.count; section++) {
@@ -569,14 +546,14 @@ - (void)_layoutVisibleCells
KKGridViewHeader *header = nil;
if (_headerViews.count > section && (header = [_headerViews objectAtIndex:section])) {
CGFloat headerPosition = [self _sectionHeightsCombinedUpToSection:section] + _gridHeaderView.frame.size.height;
- [self _configureAuxiliaryView:header inSection:section withStickPoint:headerPosition height:sectionMetrics.headerHeight];
+ [self _configureSectionView:header inSection:section withStickPoint:headerPosition height:sectionMetrics.headerHeight];
}
KKGridViewFooter *footer = nil;
if (_footerViews.count > section && (footer = [_footerViews objectAtIndex:section])) {
CGFloat footerHeight = sectionMetrics.footerHeight;
CGFloat footerPosition = [self _sectionHeightsCombinedUpToSection:section+1] + _gridHeaderView.frame.size.height - footerHeight;
- [self _configureAuxiliaryView:footer inSection:section withStickPoint:footerPosition height:footerHeight];
+ [self _configureSectionView:footer inSection:section withStickPoint:footerPosition height:footerHeight];
}
}
} completion:nil];
@@ -592,7 +569,7 @@ - (void)_cleanupCells
__unsafe_unretained KKIndexPath *path;
} cell_info_t;
- cell_info_t *cellsToRemove = (cell_info_t *)malloc(_visibleCells.count * sizeof(cell_info_t));
+ cell_info_t cellsToRemove[_visibleCells.count];
NSUInteger cellCount = 0;
for (KKIndexPath *path in _visibleCells) {
@@ -608,13 +585,11 @@ - (void)_cleanupCells
KKGridViewCell *cell = pair.cell;
[self _enqueueCell:cell withIdentifier:cell.reuseIdentifier];
- cell.frame = (CGRect){CGPointZero, _cellSize};
+ cell.frame = (CGRect){.size = _cellSize};
[cell removeFromSuperview];
[_visibleCells removeObjectForKey:pair.path];
}
-
- free(cellsToRemove);
}
- (void)_respondToBoundsChange
@@ -643,7 +618,7 @@ - (void)_performRemainingUpdatesModelOnly
}
}
-- (void)_configureAuxiliaryView:(KKGridViewViewInfo *)headerOrFooter inSection:(NSUInteger)section withStickPoint:(CGFloat)stickPoint height:(CGFloat)height
+- (void)_configureSectionView:(KKGridViewSectionInfo *)headerOrFooter inSection:(NSUInteger)section withStickPoint:(CGFloat)stickPoint height:(CGFloat)height
{
headerOrFooter.view.frame = CGRectMake(0.f, stickPoint, self.bounds.size.width, height);
headerOrFooter->stickPoint = stickPoint;
@@ -918,7 +893,7 @@ - (void)insertItemsAtIndexPaths:(NSArray *)indexPaths withAnimation:(KKGridViewA
}
} else if (update.type == KKGridViewUpdateTypeItemDelete) {
if (indexPath.section == keyPath.section) {
- if (keyPath.index - 1 > -1)
+ if (keyPath.index > 0)
[replacementSet addObject:[KKIndexPath indexPathForIndex:keyPath.index - 1 inSection:keyPath.section]];
} else {
[replacementSet addObject:keyPath];
@@ -939,13 +914,10 @@ - (void)insertItemsAtIndexPaths:(NSArray *)indexPaths withAnimation:(KKGridViewA
for (KKIndexPath *keyPath in difference) {
KKGridViewCell *cell = [_visibleCells objectForKey:keyPath];
cell.selected = [_selectedIndexPaths containsObject:keyPath];
- if (_staggerForInsertion) {
- [UIView animateWithDuration:KKGridViewDefaultAnimationDuration delay:0.0015 options:(UIViewAnimationOptionCurveEaseInOut) animations:^{
- cell.frame = [self rectForCellAtIndexPath:indexPath];
- } completion:nil];
- } else {
+
+ [KKGridView animateIf:_staggerForInsertion delay:0.0015 options:UIViewAnimationOptionCurveEaseInOut block:^{
cell.frame = [self rectForCellAtIndexPath:indexPath];
- }
+ }];
}
}
}
@@ -1012,7 +984,7 @@ - (void)_commonReload
{
[self reloadContentSize];
- void (^clearAuxiliaryViews)(NSMutableArray *) = ^(NSMutableArray *views) {
+ void (^clearSectionViews)(NSMutableArray *) = ^(NSMutableArray *views) {
for (id view in [views valueForKey:@"view"]) {
if (view != [NSNull null])
[view removeFromSuperview];
@@ -1022,7 +994,7 @@ - (void)_commonReload
};
if (_dataSourceRespondsTo.viewForHeader || _dataSourceRespondsTo.titleForHeader) {
- clearAuxiliaryViews(_headerViews);
+ clearSectionViews(_headerViews);
if (!_headerViews)
{
_headerViews = [[NSMutableArray alloc] initWithCapacity:_metrics.count];
@@ -1034,14 +1006,14 @@ - (void)_commonReload
[_headerViews addObject:header];
CGFloat position = [self _sectionHeightsCombinedUpToSection:section] + _gridHeaderView.frame.size.height;
- [self _configureAuxiliaryView:header inSection:section withStickPoint:position height:_metrics.sections[section].headerHeight];
+ [self _configureSectionView:header inSection:section withStickPoint:position height:_metrics.sections[section].headerHeight];
[self addSubview:header.view];
}
}
if (_dataSourceRespondsTo.viewForFooter || _dataSourceRespondsTo.titleForFooter) {
- clearAuxiliaryViews(_footerViews);
+ clearSectionViews(_footerViews);
if (!_footerViews)
{
_footerViews = [[NSMutableArray alloc] initWithCapacity:_metrics.count];
@@ -1054,7 +1026,7 @@ - (void)_commonReload
CGFloat footerHeight = _metrics.sections[section].footerHeight;
CGFloat position = [self _sectionHeightsCombinedUpToSection:section+1] + _gridHeaderView.frame.size.height - footerHeight;
- [self _configureAuxiliaryView:footer inSection:section withStickPoint:position height:footerHeight];
+ [self _configureSectionView:footer inSection:section withStickPoint:position height:footerHeight];
[self addSubview:footer.view];
}
@@ -1062,24 +1034,28 @@ - (void)_commonReload
// IndexView
if (_dataSourceRespondsTo.sectionIndexTitles) {
- if (_indexView)
- [_indexView removeFromSuperview];
+ [_indexView removeFromSuperview];
NSArray *indexes = [_dataSource sectionIndexTitlesForGridView:self];
- if (indexes && [indexes isKindOfClass:[NSArray class]] && [indexes count]) {
- _indexView = [[KKGridViewIndexView alloc] initWithFrame:CGRectZero];
- [_indexView setSectionIndexTitles:indexes];
+ if ([indexes isKindOfClass:[NSArray class]] && [indexes count]) {
+ if (!_indexView)
+ _indexView = [[KKGridViewIndexView alloc] initWithFrame:CGRectZero];
- __unsafe_unretained KKGridView *weakSelf = self;
+ _indexView.sectionIndexTitles = indexes;
+
+ __kk_weak KKGridView *weakSelf = self;
[_indexView setSectionTracked:^(NSUInteger section) {
KKGridView *strongSelf = weakSelf;
-
+
NSUInteger sectionToScroll = section;
if (strongSelf->_dataSourceRespondsTo.sectionForSectionIndexTitle)
sectionToScroll = [strongSelf->_dataSource gridView:strongSelf
- sectionForSectionIndexTitle:[indexes objectAtIndex:section] atIndex:section];
+ sectionForSectionIndexTitle:[indexes objectAtIndex:section]
+ atIndex:section];
- [strongSelf scrollToItemAtIndexPath:[KKIndexPath indexPathForIndex:0. inSection:sectionToScroll] animated:NO position:KKGridViewScrollPositionTop];
+ [strongSelf scrollToItemAtIndexPath:[KKIndexPath indexPathForIndex:0 inSection:sectionToScroll]
+ animated:NO
+ position:KKGridViewScrollPositionTop];
}];
[self _insertSubviewBelowScrollbar:_indexView];
@@ -1094,9 +1070,9 @@ - (void)reloadData
for (KKGridViewCell *cell in [_visibleCells allValues]) {
NSMutableSet *set = [self _reusableCellSetForIdentifier:cell.reuseIdentifier];
[set addObject:cell];
+ [cell removeFromSuperview];
}
- [[_visibleCells allValues] makeObjectsPerformSelector:@selector(removeFromSuperview)];
[_visibleCells removeAllObjects];
}
@@ -1125,17 +1101,14 @@ - (void)reloadContentSize
for (NSUInteger i = 0; i < _metrics.count; ++i) {
CGFloat heightForSection = 0.f;
- if (_metrics.count > i) {
- struct KKSectionMetrics sectionMetrics = _metrics.sections[i];
-
- heightForSection += sectionMetrics.headerHeight;
- heightForSection += sectionMetrics.footerHeight;
-
- NSUInteger numberOfRows = ceilf(sectionMetrics.itemCount / (float)_numberOfColumns);
-
- heightForSection += numberOfRows * (_cellSize.height + _cellPadding.height);
- heightForSection += (numberOfRows? _cellPadding.height:0.f);
- }
+ struct KKSectionMetrics sectionMetrics = _metrics.sections[i];
+
+ heightForSection += sectionMetrics.headerHeight + sectionMetrics.footerHeight;
+
+ NSUInteger numberOfRows = ceilf(sectionMetrics.itemCount / (float)_numberOfColumns);
+
+ heightForSection += numberOfRows * (_cellSize.height + _cellPadding.height);
+ heightForSection += (numberOfRows? _cellPadding.height:0.f);
_metrics.sections[i].sectionHeight = heightForSection;
newContentSize.height += heightForSection;
@@ -1173,11 +1146,9 @@ - (void)_reloadMetrics
.footerHeight = willDrawFooter ? 25.0 : 0.0,
.headerHeight = willDrawHeader ? 25.0 : 0.0,
.sectionHeight = 0.f,
- .itemCount = 0.f
+ .itemCount = [_dataSource gridView:self numberOfItemsInSection:index]
};
- sectionMetrics.itemCount = [_dataSource gridView:self numberOfItemsInSection:index];
-
if (_dataSourceRespondsTo.heightForHeader)
sectionMetrics.headerHeight = [_dataSource gridView:self heightForHeaderInSection:index];
if (_dataSourceRespondsTo.heightForFooter)
@@ -1247,7 +1218,7 @@ - (UIView *)_viewForFooterInSection:(NSUInteger)section
#pragma mark - Subviewinsertion
- (void)_insertSubviewBelowScrollbar:(UIView *)view {
- if (_indexView && view!=_indexView)
+ if (_indexView && view != _indexView)
[self insertSubview:view belowSubview:_indexView];
else
[self insertSubview:view atIndex:self.subviews.count - 1];
@@ -1257,35 +1228,27 @@ - (void)_insertSubviewBelowScrollbar:(UIView *)view {
- (void)scrollToItemAtIndexPath:(KKIndexPath *)indexPath animated:(BOOL)animated position:(KKGridViewScrollPosition)scrollPosition
{
- if (animated && scrollPosition != KKGridViewScrollPositionNone) {
+ CGRect cellRect = [self rectForCellAtIndexPath:indexPath];
+ if (scrollPosition == KKGridViewScrollPositionNone) {
+ [self scrollRectToVisible:cellRect animated:animated];
+ return;
+ }
+
+ if (animated) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
}
- CGFloat verticalOffset = 0.0;
-
- CGRect cellRect = [self rectForCellAtIndexPath:indexPath];
CGFloat boundsHeight = self.bounds.size.height - self.contentInset.bottom;
+ CGFloat headerPlusPadding = _metrics.sections[indexPath.section].headerHeight + self.cellPadding.height;
- switch (scrollPosition) {
- case KKGridViewScrollPositionTop:
- verticalOffset = CGRectGetMinY(cellRect) + self.contentInset.top - _metrics.sections[indexPath.section].headerHeight - self.cellPadding.height;
- break;
- case KKGridViewScrollPositionBottom:
- verticalOffset = CGRectGetMaxY(cellRect) - boundsHeight + _metrics.sections[indexPath.section].headerHeight + self.cellPadding.height;
- break;
- case KKGridViewScrollPositionMiddle:
- verticalOffset = CGRectGetMaxY(cellRect) - (boundsHeight * .5f);
- break;
- case KKGridViewScrollPositionNone:
- [self scrollRectToVisible:cellRect animated:animated];
- return;
- break;
- default:
- break;
- }
+ CGFloat offsetMap[] = {
+ [KKGridViewScrollPositionTop] = CGRectGetMinY(cellRect) + self.contentInset.top - headerPlusPadding,
+ [KKGridViewScrollPositionBottom] = CGRectGetMaxY(cellRect) - boundsHeight + headerPlusPadding,
+ [KKGridViewScrollPositionMiddle] = CGRectGetMaxY(cellRect) - (boundsHeight / 2)
+ };
- self.contentOffset = (CGPoint) { .y = verticalOffset };
+ self.contentOffset = (CGPoint) {.y = offsetMap[scrollPosition]};
if (animated)
[UIView commitAnimations];
@@ -1298,15 +1261,11 @@ - (void)selectItemsAtIndexPaths:(NSArray *)indexPaths animated:(BOOL)animated
if (!indexPaths)
return;
- if (animated) {
- [UIView beginAnimations:nil context:NULL];
- [UIView setAnimationDuration:KKGridViewDefaultAnimationDuration];
- }
- for (KKIndexPath *indexPath in indexPaths) {
- [self _selectItemAtIndexPath:indexPath];
- }
- if (animated)
- [UIView commitAnimations];
+ [KKGridView animateIf:animated delay:0.f options:0 block:^{
+ for (KKIndexPath *indexPath in indexPaths) {
+ [self _selectItemAtIndexPath:indexPath];
+ }
+ }];
}
- (void)deselectItemsAtIndexPaths:(NSArray *)indexPaths animated:(BOOL)animated
@@ -1314,15 +1273,11 @@ - (void)deselectItemsAtIndexPaths:(NSArray *)indexPaths animated:(BOOL)animated
if (!indexPaths)
return;
- if (animated) {
- [UIView beginAnimations:nil context:NULL];
- [UIView setAnimationDuration:KKGridViewDefaultAnimationDuration];
- }
- for (KKIndexPath *indexPath in indexPaths) {
- [self _deselectItemAtIndexPath:indexPath];
- }
- if (animated)
- [UIView commitAnimations];
+ [KKGridView animateIf:animated delay:0.f options:0 block:^{
+ for (KKIndexPath *indexPath in indexPaths) {
+ [self _deselectItemAtIndexPath:indexPath];
+ }
+ }];
}
- (KKIndexPath*)indexPathForSelectedCell {
@@ -1381,6 +1336,7 @@ - (void)_selectItemAtIndexPath:(KKIndexPath *)indexPath
[_selectedIndexPaths addObject:indexPath];
cell.selected = YES;
}
+
if (_delegateRespondsTo.didSelectItem) {
[_gridDelegate gridView:self didSelectItemAtIndexPath:indexPath];
}
@@ -1410,20 +1366,22 @@ - (void)_deselectItemAtIndexPath:(KKIndexPath *)indexPath
#pragma mark - Touch Handling
- (void)_handleSelection:(UILongPressGestureRecognizer *)recognizer
-{
+{
+ UIGestureRecognizerState state = recognizer.state;
+ CGPoint locationInSelf = [recognizer locationInView:self];
+
if (_indexView) {
- if (CGRectContainsPoint(_indexView.frame, [recognizer locationInView:self]) &&
- recognizer.state == UIGestureRecognizerStateBegan) {
- [self setScrollEnabled:NO];
+ if (state == UIGestureRecognizerStateBegan && CGRectContainsPoint(_indexView.frame, locationInSelf)) {
+ self.scrollEnabled = NO;
[_indexView setTracking:YES location:[recognizer locationInView:_indexView]];
return;
}
- else if (recognizer.state == UIGestureRecognizerStateChanged && _indexView.tracking) {
+ else if (state == UIGestureRecognizerStateChanged && _indexView.tracking) {
[_indexView setTracking:YES location:CGPointMake(0.0, [recognizer locationInView:_indexView].y)];
return;
}
- else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) {
- [self setScrollEnabled:YES];
+ else if ((state == UIGestureRecognizerStateEnded || state == UIGestureRecognizerStateCancelled) && _indexView.tracking) {
+ self.scrollEnabled = YES;
[_indexView setTracking:NO location:[recognizer locationInView:_indexView]];
return;
}
@@ -1432,7 +1390,7 @@ - (void)_handleSelection:(UILongPressGestureRecognizer *)recognizer
if ([self isDecelerating])
return;
- KKIndexPath *indexPath = [self indexPathForItemAtPoint:[recognizer locationInView:self]];
+ KKIndexPath *indexPath = [self indexPathForItemAtPoint:locationInSelf];
if (_delegateRespondsTo.willSelectItem)
indexPath = [_gridDelegate gridView:self willSelectItemAtIndexPath:indexPath];
@@ -1442,12 +1400,12 @@ - (void)_handleSelection:(UILongPressGestureRecognizer *)recognizer
return;
}
- if (recognizer.state == UIGestureRecognizerStateBegan) {
+ if (state == UIGestureRecognizerStateBegan) {
[self _highlightItemAtIndexPath:indexPath];
}
- else if (recognizer.state == UIGestureRecognizerStateEnded) {
- BOOL touchInSameCell = CGRectContainsPoint([self rectForCellAtIndexPath:_highlightedIndexPath], [recognizer locationInView:self]);
+ else if (state == UIGestureRecognizerStateEnded) {
+ BOOL touchInSameCell = CGRectContainsPoint([self rectForCellAtIndexPath:_highlightedIndexPath], locationInSelf);
if (touchInSameCell && ![self isDragging])
[self _selectItemAtIndexPath:indexPath];
[self _cancelHighlighting];
@@ -1470,11 +1428,20 @@ - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
- if (_indexView)
- [_indexView setFrame:CGRectMake(_indexView.frame.origin.x,
- scrollView.contentOffset.y,
- _indexView.frame.size.width,
- _indexView.frame.size.height)];
+ _indexView.frame = (CGRect) {
+ {_indexView.frame.origin.x, scrollView.contentOffset.y},
+ _indexView.frame.size
+ };
+}
+
+#pragma mark - Animation Helpers
+
++ (void)animateIf:(BOOL)animated delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options block:(void(^)())block
+{
+ if (animated)
+ [UIView animateWithDuration:KKGridViewDefaultAnimationDuration delay:delay options:options animations:block completion:nil];
+ else
+ block();
}
@end
View
360 KKGridView/KKGridViewCell.m
@@ -10,16 +10,13 @@
#import <KKGridView/KKGridView.h>
@interface KKGridViewCell ()
-
- (UIImage *)_defaultBlueBackgroundRendition;
- (void)_updateSubviewSelectionState;
-
+- (void)_layoutAccessories;
@end
@implementation KKGridViewCell {
UIButton *_badgeView;
- NSString *_badgeText;
-
UIColor *_userContentViewBackgroundColor;
BOOL _ignoreUserContentViewBackground;
}
@@ -40,7 +37,7 @@ @implementation KKGridViewCell {
+ (NSString *)cellIdentifier
{
- return NSStringFromClass([self class]);
+ return NSStringFromClass(self);
}
+ (id)cellForGridView:(KKGridView *)gridView
@@ -81,28 +78,33 @@ - (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier
}
- (void)awakeFromNib {
-
- if (!_contentView) {
- _contentView = [[UIView alloc] initWithFrame:self.bounds];
- _contentView.backgroundColor = [UIColor whiteColor];
- }
- [self addSubview:_contentView];
-
- if (!_backgroundView) {
- _backgroundView = [[UIView alloc] initWithFrame:self.bounds];
- _backgroundView.backgroundColor = [UIColor whiteColor];
- }
- [self addSubview:_backgroundView];
-
- if (!_selectedBackgroundView) {
- _selectedBackgroundView = [[UIView alloc] initWithFrame:self.bounds];
- }
- _selectedBackgroundView.hidden = YES;
- _selectedBackgroundView.alpha = 0.f;
- [self addSubview:_selectedBackgroundView];
- [self bringSubviewToFront:_contentView];
-
- [_contentView addObserver:self forKeyPath:@"backgroundColor" options:NSKeyValueObservingOptionNew context:NULL];
+ if (!_contentView) {
+ _contentView = [[UIView alloc] initWithFrame:self.bounds];
+ _contentView.backgroundColor = [UIColor whiteColor];
+ }
+
+ if (!_backgroundView) {
+ _backgroundView = [[UIView alloc] initWithFrame:self.bounds];
+ _backgroundView.backgroundColor = [UIColor whiteColor];
+ }
+
+ if (!_selectedBackgroundView) {
+ _selectedBackgroundView = [[UIView alloc] initWithFrame:self.bounds];
+ }
+
+ _selectedBackgroundView.hidden = YES;
+ _selectedBackgroundView.alpha = 0.f;
+
+ [self addSubview:_contentView];
+ [self addSubview:_backgroundView];
+ [self addSubview:_selectedBackgroundView];
+
+ [self bringSubviewToFront:_contentView];
+
+ [_contentView addObserver:self
+ forKeyPath:@"backgroundColor"
+ options:NSKeyValueObservingOptionNew
+ context:NULL];
}
- (void)dealloc
@@ -123,44 +125,61 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N
- (void)setAccessoryType:(KKGridViewCellAccessoryType)accessoryType
{
- _accessoryType = accessoryType;
- [self setNeedsLayout];
+ if (_accessoryType != accessoryType) {
+ _accessoryType = accessoryType;
+ [self setNeedsLayout];
+ }
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
- [UIView animateWithDuration:KKGridViewDefaultAnimationDuration animations:^{
- self.editing = editing;
- }];
+ if (animated) {
+ [UIView beginAnimations:nil context:NULL];
+ UIView.animationDuration = KKGridViewDefaultAnimationDuration;
+ }
+
+ self.editing = editing;
+
+ if (animated)
+ [UIView commitAnimations];
}
- (void)setSelected:(BOOL)selected
{
- _selected = selected;
- [self setNeedsLayout];
-
- if (selected && !_selectedBackgroundView.backgroundColor)
- _selectedBackgroundView.backgroundColor = [UIColor colorWithPatternImage:[self _defaultBlueBackgroundRendition]];
+ if (_selected != selected) {
+ _selected = selected;
+ [self setNeedsLayout];
+
+ if (selected && !_selectedBackgroundView.backgroundColor)
+ _selectedBackgroundView.backgroundColor = [UIColor colorWithPatternImage:[self _defaultBlueBackgroundRendition]];
+ }
}
- (void)setHighlighted:(BOOL)highlighted
{
- _highlighted = highlighted;
- [self setNeedsLayout];
-
- if (highlighted && !_selectedBackgroundView.backgroundColor)
- _selectedBackgroundView.backgroundColor = [UIColor colorWithPatternImage:[self _defaultBlueBackgroundRendition]];
+ if (_highlighted != highlighted) {
+ _highlighted = highlighted;
+ [self setNeedsLayout];
+
+ if (highlighted && !_selectedBackgroundView.backgroundColor)
+ _selectedBackgroundView.backgroundColor = [UIColor colorWithPatternImage:[self _defaultBlueBackgroundRendition]];
+ }
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
- [UIView animateWithDuration:animated ? 0.2 : 0 delay:0 options:(UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionAllowAnimatedContent) animations:^(void) {
- _selected = selected;
- _selectedBackgroundView.alpha = selected ? 1.f : 0.f;
- } completion:^(BOOL finished) {
- [self setNeedsLayout];
- }];
+ if (_selected != selected) {
+ NSTimeInterval duration = animated ? 0.2 : 0;
+ UIViewAnimationOptions opts = UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionAllowAnimatedContent;
+
+ [UIView animateWithDuration:duration delay:0 options:opts animations:^{
+ _selected = selected;
+ _selectedBackgroundView.alpha = selected ? 1.f : 0.f;
+ } completion:^(BOOL finished) {
+ [self setNeedsLayout];
+ }];
+ }
}
- (void)setSelectedBackgroundView:(UIView *)selectedBackgroundView
@@ -177,10 +196,9 @@ - (void)setSelectedBackgroundView:(UIView *)selectedBackgroundView
- (void)_updateSubviewSelectionState
{
- for (UIView *view in _contentView.subviews) {
- if ([view respondsToSelector:@selector(setSelected:)]) {
- UIButton *assumedButton = (UIButton *)view;
- assumedButton.selected = _highlighted || _selected;
+ for (UIControl *control in _contentView.subviews) {
+ if ([control respondsToSelector:@selector(setSelected:)]) {
+ control.selected = _highlighted || _selected;
}
}
}
@@ -204,179 +222,92 @@ - (void)layoutSubviews
_contentView.backgroundColor = [UIColor clearColor];
_contentView.opaque = NO;
} else {
- _contentView.backgroundColor = (_userContentViewBackgroundColor) ? _userContentViewBackgroundColor : [UIColor whiteColor];
+ _contentView.backgroundColor = _userContentViewBackgroundColor ? _userContentViewBackgroundColor : [UIColor whiteColor];
}
_selectedBackgroundView.hidden = !_selected && !_highlighted;
_backgroundView.hidden = _selected || _highlighted;
- _selectedBackgroundView.alpha = (_highlighted || _selected) ? 1.f : 0.f;
+ _selectedBackgroundView.alpha = (_selected || _highlighted) ? 1.f : 0.f;
- static NSBundle* bundle = nil;
- if (nil == bundle) {
- NSString* path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"KKGridView.bundle"];
- bundle = [NSBundle bundleWithPath:path];
- }
+ [self _layoutAccessories];
+}
+- (void)_layoutAccessories
+{
+ static const NSUInteger badgeCount = KKGridViewCellAccessoryTypeCheckmark + 1;
+ static UIImage *normalBadges[badgeCount] = {0};
+ static UIImage *pressedBadges[badgeCount] = {0};
+
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ NSString *bundlePath = [[NSBundle mainBundle].resourcePath stringByAppendingPathComponent:@"KKGridView.bundle"];
+ NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
+ UIImage *(^getBundleImage)(NSString *) = ^(NSString *n) {
+ return [UIImage imageWithContentsOfFile:[bundle pathForResource:n ofType:@"png"]];
+ };
+
+ normalBadges[KKGridViewCellAccessoryTypeBadgeExclamatory] = getBundleImage(@"failure-btn");
+ normalBadges[KKGridViewCellAccessoryTypeUnread] = getBundleImage(@"UIUnreadIndicator");
+ normalBadges[KKGridViewCellAccessoryTypeReadPartial] = getBundleImage(@"UIUnreadIndicatorPartial");
+ normalBadges[KKGridViewCellAccessoryTypeBadgeNumeric] = getBundleImage(@"failure-btn");
+ normalBadges[KKGridViewCellAccessoryTypeCheckmark] = getBundleImage(@"UIPreferencesWhiteCheck");
+
+ pressedBadges[KKGridViewCellAccessoryTypeBadgeExclamatory] = getBundleImage(@"failure-btn-pressed");
+ pressedBadges[KKGridViewCellAccessoryTypeUnread] = getBundleImage(@"UIUnreadIndicatorPressed");
+ pressedBadges[KKGridViewCellAccessoryTypeReadPartial] = getBundleImage(@"UIUnreadIndicatorPartialPressed");
+ pressedBadges[KKGridViewCellAccessoryTypeBadgeNumeric] = getBundleImage(@"failure-btn-pressed");
+ });
+
+
switch (self.accessoryType) {
case KKGridViewCellAccessoryTypeNone:
- _badgeView = nil;
- break;
+ [_badgeView removeFromSuperview];
case KKGridViewCellAccessoryTypeNew:
- break;
case KKGridViewCellAccessoryTypeInfo:
- break;
case KKGridViewCellAccessoryTypeDelete:
break;
- case KKGridViewCellAccessoryTypeBadgeExclamatory: {
- if (!_badgeView) {
- _badgeView = [[UIButton alloc] init];
- [_badgeView setBackgroundImage:[UIImage imageWithContentsOfFile:[bundle pathForResource:@"failure-btn" ofType:@"png"]] forState:UIControlStateNormal];
- [_badgeView setBackgroundImage:[UIImage imageWithContentsOfFile:[bundle pathForResource:@"failure-btn-press" ofType:@"png"]] forState:UIControlStateSelected];
- [_badgeView setShowsTouchWhenHighlighted:NO];
-
- [_contentView addSubview:_badgeView];
- }
- CGPoint point = CGPointZero;
- switch (_accessoryPosition) {
- case KKGridViewCellAccessoryPositionTopRight:
- point = CGPointMake(self.bounds.size.width - 29.f, 0.f);
- break;
- case KKGridViewCellAccessoryPositionTopLeft:
- point = CGPointZero;
- break;
- case KKGridViewCellAccessoryPositionBottomLeft:
- point = CGPointMake(0.f, (self.bounds.size.height - 29.f));
- break;
- case KKGridViewCellAccessoryPositionBottomRight:
- point = CGPointMake(self.bounds.size.width - 29.f, (self.bounds.size.height - 29.f));
- break;
- default:
- break;
- }
-
- _badgeView.frame = (CGRect){point, CGSizeMake(29.f, 29.f)};
- [_contentView bringSubviewToFront:_badgeView];
- break;
- } case KKGridViewCellAccessoryTypeUnread: {
- if (!_badgeView) {
- _badgeView = [[UIButton alloc] init];
- [_badgeView setBackgroundImage:[UIImage imageWithContentsOfFile:[bundle pathForResource:@"UIUnreadIndicator" ofType:@"png"]] forState:UIControlStateNormal];
- [_badgeView setBackgroundImage:[UIImage imageWithContentsOfFile:[bundle pathForResource:@"UIUnreadIndicatorPressed" ofType:@"png"]] forState:UIControlStateSelected];
- [_contentView addSubview:_badgeView];
- }
- CGPoint point = CGPointZero;
- switch (_accessoryPosition) {
- case KKGridViewCellAccessoryPositionTopRight:
- point = CGPointMake(self.bounds.size.width - 16.f, 3.f);
- break;
- case KKGridViewCellAccessoryPositionTopLeft:
- point = CGPointMake(3.f, 3.f);
- break;
- case KKGridViewCellAccessoryPositionBottomLeft:
- point = CGPointMake(0.f, (self.bounds.size.height - 16.f));
- break;
- case KKGridViewCellAccessoryPositionBottomRight:
- point = CGPointMake(self.bounds.size.width - 16.f, (self.bounds.size.height - 16.f));
- break;
- default:
- break;
- }
+ default: {
+ if (!_badgeView) _badgeView = [[UIButton alloc] init];
+ if (![_badgeView superview]) [_contentView addSubview:_badgeView];
- _badgeView.frame = (CGRect){point, CGSizeMake(13.f, 13.f)};
[_contentView bringSubviewToFront:_badgeView];
-
- break;
- } case KKGridViewCellAccessoryTypeReadPartial: {
- if (!_badgeView) {
- _badgeView = [[UIButton alloc] init];
- [_badgeView setBackgroundImage:[UIImage imageWithContentsOfFile:[bundle pathForResource:@"UIUnreadIndicatorPartial" ofType:@"png"]] forState:UIControlStateNormal];
- [_badgeView setBackgroundImage:[UIImage imageWithContentsOfFile:[bundle pathForResource:@"UIUnreadIndicatorPartialPressed" ofType:@"png"]] forState:UIControlStateSelected];
- [_contentView addSubview:_badgeView];
- }
- CGPoint point = CGPointZero;
- switch (_accessoryPosition) {
- case KKGridViewCellAccessoryPositionTopRight:
- point = CGPointMake(self.bounds.size.width - 16.f, 3.f);
- break;
- case KKGridViewCellAccessoryPositionTopLeft:
- point = CGPointMake(3.f, 3.f);
- break;
- case KKGridViewCellAccessoryPositionBottomLeft:
- point = CGPointMake(0.f, (self.bounds.size.height - 16.f));
- break;
- case KKGridViewCellAccessoryPositionBottomRight:
- point = CGPointMake(self.bounds.size.width - 16.f, (self.bounds.size.height - 16.f));
- break;
- default:
- break;
- }
-
- _badgeView.frame = (CGRect){point, CGSizeMake(13.f, 13.f)};
- [_contentView bringSubviewToFront:_badgeView];
- break;
- } case KKGridViewCellAccessoryTypeBadgeNumeric: {
- if (!_badgeView) {
- _badgeView = [[UIButton alloc] init];
- [_badgeView setBackgroundImage:[UIImage imageWithContentsOfFile:[bundle pathForResource:@"failure-btn" ofType:@"png"]] forState:UIControlStateNormal];
- [_badgeView setBackgroundImage:[UIImage imageWithContentsOfFile:[bundle pathForResource:@"failure-btn-press" ofType:@"png"]] forState:UIControlStateSelected];
- [_badgeView setShowsTouchWhenHighlighted:NO];
- [_contentView addSubview:_badgeView];
- }
- CGPoint point = CGPointZero;
- switch (_accessoryPosition) {
- case KKGridViewCellAccessoryPositionTopRight:
- point = CGPointMake(self.bounds.size.width - 29.f, 0.f);
- break;
- case KKGridViewCellAccessoryPositionTopLeft:
- point = CGPointZero;
- break;
- case KKGridViewCellAccessoryPositionBottomLeft:
- point = CGPointMake(0.f, (self.bounds.size.height - 29.f));
- break;
- case KKGridViewCellAccessoryPositionBottomRight:
- point = CGPointMake(self.bounds.size.width - 29.f, (self.bounds.size.height - 29.f));
- break;
- default:
- break;
- }
-
- _badgeView.frame = (CGRect){point, CGSizeMake(29.f, 29.f)};
- [_contentView bringSubviewToFront:_badgeView];
- break;
- } case KKGridViewCellAccessoryTypeCheckmark:
- if (!_badgeView) {
- _badgeView = [[UIButton alloc] init];
- [_badgeView setBackgroundImage:[UIImage imageWithContentsOfFile:[bundle pathForResource:@"UIPreferencesWhiteCheck" ofType:@"png"]] forState:UIControlStateNormal];
- _badgeView.userInteractionEnabled = NO;
- [_contentView addSubview:_badgeView];
- }
-
- CGPoint point = CGPointZero;
- switch (_accessoryPosition) {
- case KKGridViewCellAccessoryPositionTopRight:
- point = CGPointMake(self.bounds.size.width - 14.f, 0.f);
- break;
- case KKGridViewCellAccessoryPositionTopLeft:
- point = CGPointZero;
- break;
- case KKGridViewCellAccessoryPositionBottomLeft:
- point = CGPointMake(0.f, (self.bounds.size.height - 14.f));
- break;
- case KKGridViewCellAccessoryPositionBottomRight:
- point = CGPointMake(self.bounds.size.width - 14.f, (self.bounds.size.height - 14.f));
- break;
- case KKGridViewCellAccessoryPositionCenter:
- point = CGPointMake((self.bounds.size.width - 14.f) * .5f, (self.bounds.size.height - 14.f) * .5f);
- break;
- default:
- break;
- }
-
- _badgeView.frame = (CGRect){point, CGSizeMake(14.f, 14.f)};
- [_contentView bringSubviewToFront:_badgeView];
- break;
- default:
- break;
+ break;
+ }
+ }
+
+ _badgeView.userInteractionEnabled = NO;
+
+ static const struct { CGFloat sideLength; CGFloat offset; } map[] = {
+ [KKGridViewCellAccessoryTypeBadgeExclamatory] = {29.f, 0.f},
+ [KKGridViewCellAccessoryTypeUnread] = {16.f, 3.f},
+ [KKGridViewCellAccessoryTypeReadPartial] = {16.f, 3.f},
+ [KKGridViewCellAccessoryTypeBadgeNumeric] = {29.f, 0.f},
+ [KKGridViewCellAccessoryTypeCheckmark] = {14.f, 0.f},
+ };
+
+ CGFloat w = self.bounds.size.width;
+ CGFloat h = self.bounds.size.height;
+ CGFloat s = map[self.accessoryType].sideLength;
+ CGFloat o = map[self.accessoryType].offset;
+
+ CGPoint const pointMap[] = {
+ [KKGridViewCellAccessoryPositionTopRight] = {w - s, o},
+ [KKGridViewCellAccessoryPositionTopLeft] = {o, o},
+ [KKGridViewCellAccessoryPositionBottomLeft] = {.y = h - s},
+ [KKGridViewCellAccessoryPositionBottomRight] = {w - s, h - s},
+ [KKGridViewCellAccessoryPositionCenter] = {(w - s)/2, (h - s)/2}
+ };
+
+ _badgeView.frame = (CGRect){pointMap[_accessoryPosition], {s-o, s-o}};
+
+ if (normalBadges[self.accessoryType])
+ {
+ [_badgeView setBackgroundImage:normalBadges[self.accessoryType] forState:UIControlStateNormal];
+ }
+
+ if (pressedBadges[self.accessoryType])
+ {
+ [_badgeView setBackgroundImage:pressedBadges[self.accessoryType] forState:UIControlStateSelected];
}
}
@@ -384,7 +315,7 @@ - (UIImage *)_defaultBlueBackgroundRendition
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, [UIScreen mainScreen].scale);
CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
- static const CGFloat colors [] = {
+ static const CGFloat colors[] = {
0.063f, 0.459f, 0.949f, 1.0f,
0.028f, 0.26f, 0.877f, 1.0f
};
@@ -392,8 +323,9 @@ - (UIImage *)_defaultBlueBackgroundRendition
CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, colors, NULL, 2);
CGColorSpaceRelease(baseSpace), baseSpace = NULL;
- CGPoint startPoint = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMinY(self.bounds));
- CGPoint endPoint = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMaxY(self.bounds));
+ CGFloat horizontalCenter = CGRectGetMidX(self.bounds);
+ CGPoint startPoint = CGPointMake(horizontalCenter, CGRectGetMinY(self.bounds));
+ CGPoint endPoint = CGPointMake(horizontalCenter, CGRectGetMaxY(self.bounds));
CGContextDrawLinearGradient(UIGraphicsGetCurrentContext(), gradient, startPoint, endPoint, 0);
View
54 KKGridView/KKGridViewIndexView.m
@@ -35,8 +35,8 @@ + (void)initialize {
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
- [self setOpaque:NO];
- [self setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight)];
+ self.opaque = NO;
+ self.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
}
return self;
@@ -46,24 +46,26 @@ - (void)drawRect:(CGRect)rect {
// If tracking, draw background
if (_tracking) {
- [backgroundColor set];
- UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.bounds, KKGridViewIndexViewMargin, KKGridViewIndexViewMargin)
- cornerRadius:(self.bounds.size.width-2*KKGridViewIndexViewMargin)/2];
- [path fill];
+ [backgroundColor set];
+
+ CGRect insetBounds = CGRectInset(self.bounds, KKGridViewIndexViewMargin, KKGridViewIndexViewMargin);
+ CGFloat radius = (self.bounds.size.width - 2*KKGridViewIndexViewMargin) / 2;
+ [[UIBezierPath bezierPathWithRoundedRect:insetBounds cornerRadius:radius] fill];
}
NSUInteger sections = [_sectionIndexTitles count];
- CGFloat sectionHeight = (self.bounds.size.height - 2*KKGridViewIndexViewMargin)/sections;
+ CGFloat sectionHeight = (self.bounds.size.height - 2 * KKGridViewIndexViewMargin)/sections;
CGFloat currentSectionTop = KKGridViewIndexViewMargin;
// Draw the titles in the center of its section
- CGSize currentTitleSize;
- CGPoint drawingPoint;
[fontColor set];
+
for (NSString *title in _sectionIndexTitles) {
- currentTitleSize = [title sizeWithFont:font];
- drawingPoint = CGPointMake(floorf(self.bounds.size.width/2-currentTitleSize.width/2),
- floorf(currentSectionTop+(sectionHeight/2-currentTitleSize.height/2))),
+ CGSize currentTitleSize = [title sizeWithFont:font];
+ CGPoint drawingPoint = {
+ floorf(self.bounds.size.width / 2 - currentTitleSize.width / 2),
+ floorf(currentSectionTop + (sectionHeight / 2 - currentTitleSize.height / 2))
+ };
[title drawAtPoint:drawingPoint withFont:font];
currentSectionTop+=sectionHeight;
@@ -71,10 +73,11 @@ - (void)drawRect:(CGRect)rect {
}
- (void)willMoveToSuperview:(UIView *)newSuperview {
- [self setFrame:CGRectMake(newSuperview.bounds.size.width-self.frame.size.width,
- 0.0,
- self.frame.size.width,
- newSuperview.bounds.size.height)];
+ self.frame = (CGRect) {
+ .origin.x = newSuperview.bounds.size.width - self.frame.size.width,
+ .size.width = self.frame.size.width,
+ .size.height = newSuperview.bounds.size.height
+ };
}
#pragma mark - Setters
@@ -84,19 +87,20 @@ - (void)setSectionIndexTitles:(NSArray *)sectionIndexTitles {
// Look for the largest title and set the width
CGFloat maxWidth = 0.0;
- CGFloat currentWidth = 0.0;
+
for (NSString *title in _sectionIndexTitles) {
- currentWidth = [title sizeWithFont:font].width;
+ CGFloat currentWidth = [title sizeWithFont:font].width;
if (currentWidth > maxWidth)
maxWidth = currentWidth;
}
- [self setFrame:CGRectMake(self.frame.origin.x,
- self.frame.origin.x,
- maxWidth+(2*KKGridViewIndexViewPadding+2*KKGridViewIndexViewMargin),
- self.frame.size.height)];
-
+ CGSize size = {
+ maxWidth + 2*KKGridViewIndexViewPadding + 2*KKGridViewIndexViewMargin,
+ self.frame.size.height
+ };
+
+ self.frame = (CGRect){self.frame.origin, size};
[self setNeedsDisplay];
}
@@ -107,7 +111,7 @@ - (void)setTracking:(BOOL)tracking location:(CGPoint)location {
if (_tracking && CGRectContainsPoint(self.bounds, location)) {
NSUInteger sections = [_sectionIndexTitles count];
CGFloat sectionHeight = (self.bounds.size.height - 2*KKGridViewIndexViewMargin)/sections;
- location.y-=KKGridViewIndexViewMargin;
+ location.y -= KKGridViewIndexViewMargin;
_lastTrackingSection = floorf(abs(location.y)/sectionHeight);
@@ -116,8 +120,8 @@ - (void)setTracking:(BOOL)tracking location:(CGPoint)location {
if (_sectionTracked)
_sectionTracked(_lastTrackingSection);
-
}
+
[self setNeedsDisplay];
}
View
8 KKGridView/KKGridViewViewInfo.h → KKGridView/KKGridViewSectionInfo.h
@@ -1,12 +1,12 @@
//
-// KKGridViewViewInfo.h
+// KKGridViewSectionInfo.h
// KKGridView
//
// Created by Jonathan Sterling on 7/31/11.
// Copyright 2011 Giulio Petek, Jonathan Sterling, and Kolin Krewinkel. All rights reserved.
//
-@interface KKGridViewViewInfo : NSObject {
+@interface KKGridViewSectionInfo : NSObject {
@package
CGFloat stickPoint;
NSUInteger section;
@@ -20,8 +20,8 @@
@end
-@interface KKGridViewFooter : KKGridViewViewInfo
+@interface KKGridViewFooter : KKGridViewSectionInfo
@end
-@interface KKGridViewHeader : KKGridViewViewInfo
+@interface KKGridViewHeader : KKGridViewSectionInfo
@end
View
6 KKGridView/KKGridViewViewInfo.m → KKGridView/KKGridViewSectionInfo.m
@@ -1,14 +1,14 @@
//
-// KKGridViewViewInfo.m
+// KKGridViewSectionInfo.m
// KKGridView
//
// Created by Jonathan Sterling on 7/31/11.
// Copyright 2011 Giulio Petek, Jonathan Sterling, and Kolin Krewinkel. All rights reserved.
//
-#import <KKGridView/KKGridViewViewInfo.h>
+#import <KKGridView/KKGridViewSectionInfo.h>
-@implementation KKGridViewViewInfo
+@implementation KKGridViewSectionInfo
@synthesize view = _view;
View
14 KKGridView/KKGridViewUpdate.m
@@ -32,19 +32,21 @@ - (id)initWithIndexPath:(KKIndexPath *)indexPath isSectionUpdate:(BOOL)sectionUp
+ (id)updateWithIndexPath:(KKIndexPath *)indexPath isSectionUpdate:(BOOL)sectionUpdate type:(KKGridViewUpdateType)type animation:(KKGridViewAnimation)animation
{
- id retVal = [[[self class] alloc] initWithIndexPath:indexPath isSectionUpdate:sectionUpdate type:type animation:animation];
- return retVal;
+ return [[self alloc] initWithIndexPath:indexPath
+ isSectionUpdate:sectionUpdate
+ type:type
+ animation:animation];
}
- (NSString *)description
{
- return [NSString stringWithFormat:@"KKGridViewUpdate - IndexPath: %@, Type: %d, Section Update: %i", _indexPath, _type, _sectionUpdate];
+ return [NSString stringWithFormat:@"KKGridViewUpdate - IndexPath: %@, Type: %d, Section Update: %i",
+ _indexPath, _type, _sectionUpdate];
}
-- (BOOL)isEqual:(id)object
+- (BOOL)isEqual:(KKGridViewUpdate *)update
{
- KKGridViewUpdate *update = (KKGridViewUpdate *)object;
- return ([_indexPath isEqual:update.indexPath] && _sectionUpdate == update.sectionUpdate && _type == update.type && _animation == update.animation);
+ return [_indexPath isEqual:update.indexPath] && _sectionUpdate == update.sectionUpdate && _type == update.type && _animation == update.animation;
}
- (NSUInteger)hash
View
25 KKGridView/KKIndexPath.m
@@ -19,30 +19,32 @@ - (id)initWithIndex:(NSUInteger)index section:(NSUInteger)section
_index = index;
_section = section;
}
-
+
return self;
}
-- (NSComparisonResult)compare:(id)object
+- (NSComparisonResult)compare:(KKIndexPath *)otherIndexPath
{
- KKIndexPath *otherIndexPath = (KKIndexPath *)object;
-// Identical comparison
+ // Identical comparison
if (otherIndexPath.section == self.section && otherIndexPath.index == self.index) {
return NSOrderedSame;
}
-// Sectional comparison
+
+ // Sectional comparison
if (otherIndexPath.section > self.section) {
return NSOrderedAscending;
} else if (otherIndexPath.section < self.section) {
return NSOrderedDescending;
}
-// Inter-section index comparison
+
+ // Inter-section index comparison
if (otherIndexPath.index > self.index) {
return NSOrderedAscending;
} else if (otherIndexPath.index < self.index) {
return NSOrderedDescending;
}
-// No result could be found (this should never happen, kept in to keep the compiler happy)
+
+ // No result could be found (this should never happen, kept in to keep the compiler happy)
return NSOrderedSame;
}
@@ -65,7 +67,6 @@ + (id)indexPathForIndex:(NSUInteger)index inSection:(NSUInteger)section
- (id)initWithNSIndexPath:(NSIndexPath *)indexPath
{
if ((self = [super init])) {
-// Simple name change/assignment..
self.index = indexPath.row;
self.section = indexPath.section;
}
@@ -78,13 +79,12 @@ + (id)indexPathWithNSIndexPath:(NSIndexPath *)indexPath
return [[self alloc] initWithNSIndexPath:indexPath];
}
-- (BOOL)isEqual:(id)object
+- (BOOL)isEqual:(KKIndexPath *)indexPath
{
- if (object == self) {
+ if (indexPath == self) {
return YES;
}
- KKIndexPath *indexPath = (KKIndexPath *)object;
return (indexPath->_index == _index && indexPath->_section == _section);
}
@@ -105,7 +105,8 @@ - (id)copyWithZone:(NSZone *)zone
- (NSString *)description
{
- return [NSString stringWithFormat:@"%@ {Index: %i; Section: %i}", NSStringFromClass([self class]), _index, _section];
+ return [NSString stringWithFormat:@"%@ {Index: %i; Section: %i}",
+ NSStringFromClass([self class]), _index, _section];
}
#pragma mark - KKIndexPath to NSIndexPath
View
75 README.md
@@ -1,28 +1,42 @@
<div style="width:768px; height: 200px; position: relative; margin: 0 auto;">
<img style="position: relative; width: 768px; height: 200px; margin: 0;" src="http://f.cl.ly/items/1c230w0U2d3H3I021338/KKGridViewBanner.png" alt="KKGridView"/>
</div>
-High-performance iOS grid view (MIT license). **Requirements**: you need
-to build `KKGridView` with a compiler that supports *Automatic Reference
-Counting*. We know this stings at first, but we strongly believe that
-the future is better served by requiring this now. Moreover, the move to
-ARC improved `KKGridView`'s performance greatly. Remember that your
-project need not use ARC to include `KKGridView`.
-### Contributing
-If you see something you don't like, you are always welcome to submit it
-as an issue. But if you can find it in your heart, we'd be so grateful
-if you would fix it yourself and send us a pull request. We promise not
-to bite!
+High-performance iOS grid view (MIT license). **Requirements**: you
+need to build `KKGridView` with a compiler that supports *Automatic
+Reference Counting*. We know this stings at first, but we strongly
+believe that the future is better served by requiring this
+now. Moreover, the move to ARC improved `KKGridView`'s performance
+greatly. Remember that your project need not use ARC to include
+`KKGridView`.
+
+### Contributing If you see something you don't like, you are always
+welcome to submit it as an issue. But if you can find it in your
+heart, we'd be so grateful if you would fix it yourself and send us a
+pull request. We promise not to bite!
##Current Issues
-Most features, bugs, and missing items for the project are in the Issues section. Currently, there are placement issues after inserting. We were initially going to fix these before public release, but instead decided to release now and allow outside contribution.
-Other than that, editing and selection are the only things that need work.
+Most features, bugs, and missing items for the project are in the
+Issues section. Currently, there are placement issues after
+inserting. We were initially going to fix these before public
+release, but instead decided to release now and allow outside
+contribution. Other than that, editing and selection are the only
+things that need work.
##Motivations
-`KKGridView` was created in July 2011 for usage in a few of the apps I was working on. When I discovered that this would be both very difficult and time consuming, I sought out the help of [Giulio Petek](http://twitter.com/GiloTM) and [Jonathan Sterling](http://twitter.com/jonsterling). Additionally, we brought on [Kyle Hickinson](http://twitter.com/kylehickinson), [Matthias Tretter](http://twitter.com/myell0w), and most recently, [Peter Steinberger](http://twitter.com/steipete). Luckily, all of my fellow collaborators shared the common opinion that all of the grid views available now are slow, feature-incomplete, and coded in an inextensible fashion. With this in mind, we set out to create the best grid view component available for iOS to-date.
+`KKGridView` was created in July 2011 for usage in a few of the apps I
+was working on. When I discovered that this would be both very
+difficult and time consuming, I sought out the help of [Giulio
+Petek](http://twitter.com/GiloTM) and [Jonathan
+Sterling](http://twitter.com/jonsterling). Additionally, we brought
+on [Kyle Hickinson](http://twitter.com/kylehickinson), [Matthias
+Tretter](http://twitter.com/myell0w), and most recently, [Peter
+Steinberger](http://twitter.com/steipete). We had all been frustrated
+by the existing grid view components; with this in mind, we set out to
+create the best grid view component available for iOS to-date.
##Goals
@@ -102,23 +116,7 @@ Alternatively, you can add the grid to your view-hierarchy.
~~~~objc
- (NSUInteger)gridView:(KKGridView *)gridView numberOfItemsInSection:(NSUInteger)section
{
- switch (section) {
- case 0:
- return kFirstSectionCount;
- break;
- case 1:
- return 15;
- break;
- case 2:
- return 10;
- break;
- case 3:
- return 5;
- break;
- default:
- return 0;
- break;
- }
+ return kCellCounts[section];
}
~~~~
@@ -127,26 +125,23 @@ Optionally, you can specify how many section you would like in the grid. *(Defau
~~~~objc
- (NSUInteger)numberOfSectionsInGridView:(KKGridView *)gridView
{
- return kNumSection;
+ return kNumSections;
}
~~~~
-The last required method is to return a cell, just like UITableView. We've made it easier on you, though.
-
-*`KKIndexPath` works in just the same way as `NSIndexPath`, only `-row` is replaced with `-index`.*
-
-*`KKGridViewCell`, like `UITableViewCell`, is designed to be subclassed.*
+The last required method is to return a cell, just like UITableView.
+We've made it easier on you, though. `KKIndexPath` works in just the
+same way as `NSIndexPath`, only `-row` is replaced with
+`-index`. `KKGridViewCell`, like `UITableViewCell`, is designed to be
+subclassed.*
~~~~objc
- (KKGridViewCell *)gridView:(KKGridView *)gridView cellForRowAtIndexPath:(KKIndexPath *)indexPath
{
KKGridViewCell *cell = [KKGridViewCell cellForGridView:gridView];
-
cell.backgroundColor = [UIColor lightGrayColor];
-
return cell;
}
~~~~
-
There are no required delegate methods, though all that are implemented in `UITableView` will soon be available in `KKGridView`.
Please sign in to comment.
Something went wrong with that request. Please try again.