Permalink
Browse files

Merge pull request #252 from cysp/for-review/decoration-views

Implement Decoration views
  • Loading branch information...
2 parents 5b2e22b + 6ce57ce commit 8f6c5401b127afc55a0c93bf196d1c641e8ac165 @steipete committed Mar 5, 2013
@@ -10,6 +10,7 @@
#import "PSTCollectionViewData.h"
#import "PSTCollectionViewCell.h"
#import "PSTCollectionViewLayout.h"
+#import "PSTCollectionViewLayout+Internals.h"
#import "PSTCollectionViewFlowLayout.h"
#import "PSTCollectionViewItemKey.h"
#import "PSTCollectionViewUpdateItem.h"
@@ -42,6 +43,7 @@ @interface PSTCollectionView() <UIScrollViewDelegate> {
NSMutableSet *_indexPathsForSelectedItems;
NSMutableDictionary *_cellReuseQueues;
NSMutableDictionary *_supplementaryViewReuseQueues;
+ NSMutableDictionary *_decorationViewReuseQueues;
NSMutableSet *_indexPathsForHighlightedItems;
int _reloadingSuspendedCount;
PSTCollectionReusableView *_firstResponderView;
@@ -140,6 +142,7 @@ static void PSTCollectionViewCommonSetup(PSTCollectionView *_self) {
_self->_indexPathsForHighlightedItems = [NSMutableSet new];
_self->_cellReuseQueues = [NSMutableDictionary new];
_self->_supplementaryViewReuseQueues = [NSMutableDictionary new];
+ _self->_decorationViewReuseQueues = [NSMutableDictionary new];
_self->_allVisibleViewsDict = [NSMutableDictionary new];
_self->_cellClassDict = [NSMutableDictionary new];
_self->_cellNibDict = [NSMutableDictionary new];
@@ -499,6 +502,51 @@ - (id)dequeueReusableSupplementaryViewOfKind:(NSString *)elementKind withReuseId
return view;
}
+- (id)dequeueReusableOrCreateDecorationViewOfKind:(NSString *)elementKind forIndexPath:(NSIndexPath *)indexPath {
+ NSMutableArray *reusableViews = _decorationViewReuseQueues[elementKind];
+ PSTCollectionReusableView *view = [reusableViews lastObject];
+ PSTCollectionViewLayout *collectionViewLayout = self.collectionViewLayout;
+ PSTCollectionViewLayoutAttributes *attributes = [collectionViewLayout layoutAttributesForDecorationViewOfKind:elementKind atIndexPath:indexPath];
+
+ if (view) {
+ [reusableViews removeObjectAtIndex:reusableViews.count - 1];
+ } else {
+ NSDictionary *decorationViewNibDict = collectionViewLayout.decorationViewNibDict;
+ NSDictionary *decorationViewExternalObjects = collectionViewLayout.decorationViewExternalObjectsTables;
+ if (decorationViewNibDict[elementKind]) {
+ // supplementary view was registered via registerNib:forCellWithReuseIdentifier:
+ UINib *supplementaryViewNib = decorationViewNibDict[elementKind];
+ NSDictionary *externalObjects = decorationViewExternalObjects[elementKind];
+ if (externalObjects) {
+ view = [supplementaryViewNib instantiateWithOwner:self options:@{UINibExternalObjects:externalObjects}][0];
+ } else {
+ view = [supplementaryViewNib instantiateWithOwner:self options:0][0];
+ }
+ } else {
+ NSDictionary *decorationViewClassDict = collectionViewLayout.decorationViewClassDict;
+ Class viewClass = decorationViewClassDict[elementKind];
+ Class reusableViewClass = NSClassFromString(@"UICollectionReusableView");
+ if (reusableViewClass && [viewClass isEqual:reusableViewClass]) {
+ viewClass = [PSTCollectionReusableView class];
+ }
+ if (viewClass == nil) {
+ @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"Class not registered for identifier %@", elementKind] userInfo:nil];
+ }
+ if (attributes) {
+ view = [[viewClass alloc] initWithFrame:attributes.frame];
+ } else {
+ view = [viewClass new];
+ }
+ }
+ view.collectionView = self;
+ view.reuseIdentifier = elementKind;
+ }
+
+ [view applyLayoutAttributes:attributes];
+
+ return view;
+}
+
- (NSArray *)allCells {
return [[_allVisibleViewsDict allValues] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
return [evaluatedObject isKindOfClass:[PSTCollectionViewCell class]];
@@ -1078,9 +1126,9 @@ - (void)setCollectionViewLayout:(PSTCollectionViewLayout *)layout animated:(BOOL
PSTCollectionViewLayoutAttributes *newAttr = nil;
if(newKey.type == PSTCollectionViewItemTypeDecorationView) {
- prevAttr = [self.collectionViewLayout layoutAttributesForDecorationViewWithReuseIdentifier:attr.representedElementKind
+ prevAttr = [self.collectionViewLayout layoutAttributesForDecorationViewOfKind:attr.representedElementKind
atIndexPath:newKey.indexPath];
- newAttr = [layout layoutAttributesForDecorationViewWithReuseIdentifier:attr.representedElementKind
+ newAttr = [layout layoutAttributesForDecorationViewOfKind:attr.representedElementKind
atIndexPath:newKey.indexPath];
}
else if(newKey.type == PSTCollectionViewItemTypeCell) {
@@ -1106,16 +1154,16 @@ - (void)setCollectionViewLayout:(PSTCollectionViewLayout *)layout animated:(BOOL
if(key.type == PSTCollectionViewItemTypeDecorationView) {
PSTCollectionReusableView *decorView = _allVisibleViewsDict[key];
- prevAttr = [self.collectionViewLayout layoutAttributesForDecorationViewWithReuseIdentifier:decorView.reuseIdentifier
+ prevAttr = [self.collectionViewLayout layoutAttributesForDecorationViewOfKind:decorView.reuseIdentifier
atIndexPath:key.indexPath];
- newAttr = [layout layoutAttributesForDecorationViewWithReuseIdentifier:decorView.reuseIdentifier
+ newAttr = [layout layoutAttributesForDecorationViewOfKind:decorView.reuseIdentifier
atIndexPath:key.indexPath];
}
else if(key.type == PSTCollectionViewItemTypeCell) {
prevAttr = [self.collectionViewLayout layoutAttributesForItemAtIndexPath:key.indexPath];
newAttr = [layout layoutAttributesForItemAtIndexPath:key.indexPath];
}
- else {
+ else if(key.type == PSTCollectionViewItemTypeSupplementaryView) {
PSTCollectionReusableView* suuplView = _allVisibleViewsDict[key];
prevAttr = [self.collectionViewLayout layoutAttributesForSupplementaryViewOfKind:suuplView.layoutAttributes.representedElementKind
atIndexPath:key.indexPath];
@@ -1146,6 +1194,17 @@ - (void)setCollectionViewLayout:(PSTCollectionViewLayout *)layout animated:(BOOL
view = [self createPreparedSupplementaryViewForElementOfKind:attrs.representedElementKind
atIndexPath:attrs.indexPath
withLayoutAttributes:attrs];
+ _allVisibleViewsDict[key] = view;
+ [self addControlledSubview:view];
+ }
+ }
+ else if(key.type == PSTCollectionViewItemTypeDecorationView) {
+ PSTCollectionReusableView *view = _allVisibleViewsDict[key];
+ if (!view) {
+ PSTCollectionViewLayoutAttributes *attrs = layoutInterchangeData[key][@"previousLayoutInfos"];
+ view = [self dequeueReusableOrCreateDecorationViewOfKind:attrs.reuseIdentifier forIndexPath:attrs.indexPath];
+ _allVisibleViewsDict[key] = view;
+ [self addControlledSubview:view];
}
}
};
@@ -1175,6 +1234,10 @@ - (void)setCollectionViewLayout:(PSTCollectionViewLayout *)layout animated:(BOOL
[self reuseSupplementaryView:_allVisibleViewsDict[key]];
[toRemove addObject:key];
}
+ else if(key.type == PSTCollectionViewItemTypeDecorationView) {
+ [self reuseDecorationView:_allVisibleViewsDict[key]];
+ [toRemove addObject:key];
+ }
}
}
@@ -1337,7 +1400,9 @@ - (void)updateVisibleCellsNow:(BOOL)now {
view = [self createPreparedSupplementaryViewForElementOfKind:layoutAttributes.representedElementKind
atIndexPath:layoutAttributes.indexPath
withLayoutAttributes:layoutAttributes];
- }
+ } else if (itemKey.type == PSTCollectionViewItemTypeDecorationView) {
+ view = [self dequeueReusableOrCreateDecorationViewOfKind:layoutAttributes.reuseIdentifier forIndexPath:layoutAttributes.indexPath];
+ }
// Supplementary views are optional
if (view) {
@@ -1368,13 +1433,16 @@ - (void)updateVisibleCellsNow:(BOOL)now {
[self.delegate collectionView:self didEndDisplayingCell:(PSTCollectionViewCell *)reusableView forItemAtIndexPath:itemKey.indexPath];
}
[self reuseCell:(PSTCollectionViewCell *)reusableView];
- }else if(itemKey.type == PSTCollectionViewItemTypeSupplementaryView) {
+ }
+ else if(itemKey.type == PSTCollectionViewItemTypeSupplementaryView) {
if (_collectionViewFlags.delegateDidEndDisplayingSupplementaryView) {
[self.delegate collectionView:self didEndDisplayingSupplementaryView:reusableView forElementOfKind:itemKey.identifier atIndexPath:itemKey.indexPath];
}
[self reuseSupplementaryView:reusableView];
}
- // TODO: decoration views etc?
+ else if(itemKey.type == PSTCollectionViewItemTypeDecorationView) {
+ [self reuseDecorationView:reusableView];
+ }
}
}
}
@@ -1436,6 +1504,11 @@ - (void)reuseSupplementaryView:(PSTCollectionReusableView *)supplementaryView {
[self queueReusableView:supplementaryView inQueue:_supplementaryViewReuseQueues];
}
+// enqueue decoration view for reuse
+- (void)reuseDecorationView:(PSTCollectionReusableView *)decorationView {
+ [self queueReusableView:decorationView inQueue:_decorationViewReuseQueues];
+}
+
- (void)addControlledSubview:(PSTCollectionReusableView *)subview {
// avoids placing views above the scroll indicator
// If the collection view is not displaying scrollIndicators then self.subviews.count can be 0.
@@ -1694,6 +1767,8 @@ - (void)updateWithItems:(NSArray *)items {
[self reuseCell:(PSTCollectionViewCell *)view];
} else if (key.type == PSTCollectionViewItemTypeSupplementaryView) {
[self reuseSupplementaryView:view];
+ } else if (key.type == PSTCollectionViewItemTypeDecorationView) {
+ [self reuseDecorationView:view];
}
}
}];
@@ -95,7 +95,8 @@ - (void)validateLayoutInRect:(CGRect)rect {
self.cachedLayoutAttributes = [[self.layout layoutAttributesForElementsInRect:rect] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(PSTCollectionViewLayoutAttributes *evaluatedObject, NSDictionary *bindings) {
return ([evaluatedObject isKindOfClass:[PSTCollectionViewLayoutAttributes class]] &&
([evaluatedObject isCell]||
- [evaluatedObject isSupplementaryView]));
+ [evaluatedObject isSupplementaryView]||
+ [evaluatedObject isDecorationView]));
}]];
}
}
@@ -36,8 +36,8 @@ + (id)collectionItemKeyForLayoutAttributes:(PSTCollectionViewLayoutAttributes *)
+ (id)collectionItemKeyForDecorationViewOfKind:(NSString *)elementKind andIndexPath:(NSIndexPath *)indexPath {
PSTCollectionViewItemKey *key = [[self class] new];
key.indexPath = indexPath;
- key.identifier = elementKind;
key.type = PSTCollectionViewItemTypeDecorationView;
+ key.identifier = elementKind;
return key;
}
@@ -0,0 +1,18 @@
+//
+// PSTCollectionViewLayout+Internals.h
+// FMPSTCollectionView
+//
+// Created by Scott Talbot on 27/02/13.
+// Copyright (c) 2013 Scott Talbot. All rights reserved.
+//
+
+#import "PSTCollectionViewLayout.h"
+
+
+@interface PSTCollectionViewLayout (Internals)
+
+@property (nonatomic,copy,readonly) NSDictionary *decorationViewClassDict;
+@property (nonatomic,copy,readonly) NSDictionary *decorationViewNibDict;
+@property (nonatomic,copy,readonly) NSDictionary *decorationViewExternalObjectsTables;
+
+@end
@@ -32,7 +32,7 @@ typedef NS_ENUM(NSUInteger, PSTCollectionViewItemType) {
+ (instancetype)layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath;
+ (instancetype)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind withIndexPath:(NSIndexPath *)indexPath;
-+ (instancetype)layoutAttributesForDecorationViewWithReuseIdentifier:(NSString *)reuseIdentifier withIndexPath:(NSIndexPath*)indexPath;
++ (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)kind withIndexPath:(NSIndexPath*)indexPath;
/*
+ (id)layoutAttributesForDecorationViewOfKind:(id)arg1 withIndexPath:(id)arg2;
@@ -42,6 +42,7 @@ typedef NS_ENUM(NSUInteger, PSTCollectionViewItemType) {
@end
@interface PSTCollectionViewLayoutAttributes(Private)
+@property (nonatomic, copy, readonly) NSString *reuseIdentifier;
@property (nonatomic, readonly) NSString *representedElementKind;
@property (nonatomic, readonly) PSTCollectionViewItemType representedElementCategory;
- (BOOL)isDecorationView;
@@ -63,8 +64,8 @@ extern NSString *const PSTCollectionViewLayoutAwokeFromNib;
- (void)invalidateLayout;
/// @name Registering Decoration Views
-- (void)registerClass:(Class)viewClass forDecorationViewWithReuseIdentifier:(NSString *)identifier;
-- (void)registerNib:(UINib *)nib forDecorationViewWithReuseIdentifier:(NSString *)identifier;
+- (void)registerClass:(Class)viewClass forDecorationViewOfKind:(NSString *)kind;
+- (void)registerNib:(UINib *)nib forDecorationViewOfKind:(NSString *)kind;
@end
@@ -85,7 +86,7 @@ extern NSString *const PSTCollectionViewLayoutAwokeFromNib;
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect; // return an array layout attributes instances for all the views in the given rect
- (PSTCollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
- (PSTCollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
-- (PSTCollectionViewLayoutAttributes *)layoutAttributesForDecorationViewWithReuseIdentifier:(NSString*)identifier atIndexPath:(NSIndexPath *)indexPath;
+- (PSTCollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString*)kind atIndexPath:(NSIndexPath *)indexPath;
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds; // return YES to cause the collection view to requery the layout for geometry information
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity; // return a point at which to rest after scrolling - for layouts that want snap-to-point scrolling behavior
@@ -115,4 +116,5 @@ extern NSString *const PSTCollectionViewLayoutAwokeFromNib;
@interface PSTCollectionViewLayout (Private)
- (void)setCollectionViewBoundsSize:(CGSize)size;
+- (PSTCollectionReusableView *)decorationViewForCollectionView:(PSTCollectionView *)collectionView withReuseIdentifier:(NSString *)reuseIdentifier indexPath:(NSIndexPath *)indexPath;
@end
@@ -60,10 +60,10 @@ + (instancetype)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKi
return attributes;
}
-+ (instancetype)layoutAttributesForDecorationViewWithReuseIdentifier:(NSString *)reuseIdentifier withIndexPath:(NSIndexPath *)indexPath {
++ (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)kind withIndexPath:(NSIndexPath *)indexPath {
PSTCollectionViewLayoutAttributes *attributes = [self new];
attributes.elementKind = PSTCollectionElementKindDecorationView;
- attributes.reuseIdentifier = reuseIdentifier;
+ attributes.reuseIdentifier = kind;
attributes.indexPath = indexPath;
return attributes;
}
@@ -207,6 +207,9 @@ @interface PSTCollectionViewLayout() {
NSMutableDictionary *_decorationViewExternalObjectsTables;
}
@property (nonatomic, unsafe_unretained) PSTCollectionView *collectionView;
+@property (nonatomic,copy,readonly) NSDictionary *decorationViewClassDict;
+@property (nonatomic,copy,readonly) NSDictionary *decorationViewNibDict;
+@property (nonatomic,copy,readonly) NSDictionary *decorationViewExternalObjectsTables;
@end
NSString *const PSTCollectionViewLayoutAwokeFromNib = @"PSTCollectionViewLayoutAwokeFromNib";
@@ -407,10 +410,12 @@ - (void)finalizeCollectionViewUpdates {
///////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Registering Decoration Views
-- (void)registerClass:(Class)viewClass forDecorationViewWithReuseIdentifier:(NSString *)identifier {
+- (void)registerClass:(Class)viewClass forDecorationViewOfKind:(NSString *)kind {
+ [_decorationViewClassDict setObject:viewClass forKey:kind];
}
-- (void)registerNib:(UINib *)nib forDecorationViewWithReuseIdentifier:(NSString *)identifier {
+- (void)registerNib:(UINib *)nib forDecorationViewOfKind:(NSString *)kind {
+ [_decorationViewNibDict setObject:nib forKey:kind];
}
///////////////////////////////////////////////////////////////////////////////////////////

0 comments on commit 8f6c540

Please sign in to comment.