Skip to content

Commit

Permalink
Added header
Browse files Browse the repository at this point in the history
  • Loading branch information
paweldudek committed Jan 14, 2016
1 parent ebc2abd commit 31d921c
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 32 deletions.
20 changes: 11 additions & 9 deletions CarouselCollectionViewLayout.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
43078F6A197BD9FD0025ECBF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43078F4F197BD9FD0025ECBF /* Foundation.framework */; };
43078F6B197BD9FD0025ECBF /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43078F53197BD9FD0025ECBF /* UIKit.framework */; };
43078F75197BD9FD0025ECBF /* CarouselLayoutTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 43078F74197BD9FD0025ECBF /* CarouselLayoutTests.m */; };
B27A913BFA596301C18A9698 /* PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.m in Sources */ = {isa = PBXBuildFile; fileRef = B27A966E3FC40E0996945370 /* PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.m */; };
B27A94D3F3143E09C71A455F /* PBDCarouselCollectionViewLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = B27A9F7C36FCCD1A28D832CE /* PBDCarouselCollectionViewLayout.m */; };
B27A96663940BFABA727FAC0 /* CarouselCollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B27A954C849FCCE3E366BB70 /* CarouselCollectionViewController.m */; };
B27A9AA6B040EA3A34248564 /* PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.m in Sources */ = {isa = PBXBuildFile; fileRef = B27A96430E04235FEF987259 /* PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.m */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -51,10 +51,11 @@
439841EE1C47E28600719676 /* CarouselCollectionViewLayoutTests-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CarouselCollectionViewLayoutTests-Prefix.pch"; sourceTree = "<group>"; };
439841EF1C47E28600719676 /* CarouselCollectionViewLayoutTests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "CarouselCollectionViewLayoutTests-Info.plist"; sourceTree = "<group>"; };
B27A900D6191713D16CE53F3 /* CarouselCollectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CarouselCollectionViewController.h; sourceTree = "<group>"; };
B27A92408CE32697829986F2 /* PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.h; sourceTree = "<group>"; };
B27A92B41B76EEAE062EF3A4 /* PBDCarouselCollectionViewLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBDCarouselCollectionViewLayout.h; sourceTree = "<group>"; };
B27A954C849FCCE3E366BB70 /* CarouselCollectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CarouselCollectionViewController.m; sourceTree = "<group>"; };
B27A966E3FC40E0996945370 /* PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.m; sourceTree = "<group>"; };
B27A96430E04235FEF987259 /* PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.m; sourceTree = "<group>"; };
B27A9D603D06657B3AFAFEF8 /* PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.h; sourceTree = "<group>"; };
B27A9E68A4FA40042C24F895 /* PBDCarouselCollectionViewLayoutPropertiesCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBDCarouselCollectionViewLayoutPropertiesCache.h; sourceTree = "<group>"; };
B27A9F7C36FCCD1A28D832CE /* PBDCarouselCollectionViewLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBDCarouselCollectionViewLayout.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -179,21 +180,22 @@
path = Classes;
sourceTree = "<group>";
};
B27A981EA672C5FE98221A8F /* Helpers */ = {
B27A9945B6C04DDA15B37511 /* Internal */ = {
isa = PBXGroup;
children = (
B27A966E3FC40E0996945370 /* PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.m */,
B27A92408CE32697829986F2 /* PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.h */,
B27A96430E04235FEF987259 /* PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.m */,
B27A9D603D06657B3AFAFEF8 /* PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.h */,
B27A9E68A4FA40042C24F895 /* PBDCarouselCollectionViewLayoutPropertiesCache.h */,
);
path = Helpers;
path = Internal;
sourceTree = "<group>";
};
B27A9E6A011735C5D4F66808 /* Lib */ = {
isa = PBXGroup;
children = (
B27A92B41B76EEAE062EF3A4 /* PBDCarouselCollectionViewLayout.h */,
B27A9F7C36FCCD1A28D832CE /* PBDCarouselCollectionViewLayout.m */,
B27A981EA672C5FE98221A8F /* Helpers */,
B27A9945B6C04DDA15B37511 /* Internal */,
);
path = Lib;
sourceTree = "<group>";
Expand Down Expand Up @@ -296,7 +298,7 @@
43078F5C197BD9FD0025ECBF /* main.m in Sources */,
B27A94D3F3143E09C71A455F /* PBDCarouselCollectionViewLayout.m in Sources */,
B27A96663940BFABA727FAC0 /* CarouselCollectionViewController.m in Sources */,
B27A913BFA596301C18A9698 /* PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.m in Sources */,
B27A9AA6B040EA3A34248564 /* PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ - (id)init {
PBDCarouselCollectionViewLayout *layout = [[PBDCarouselCollectionViewLayout alloc] init];
layout.itemSize = CGSizeMake(280, 240);
layout.interItemSpace = 20;
layout.headerSize = CGSizeMake(100, 490);
self = [super initWithCollectionViewLayout:layout];
if (self) {

Expand All @@ -27,6 +28,9 @@ - (void)viewDidLoad {

self.collectionView.decelerationRate = UIScrollViewDecelerationRateFast;
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"Cell"];
[self.collectionView registerClass:[UICollectionReusableView class]
forSupplementaryViewOfKind:PBDCollectionElementKindSectionHeader
withReuseIdentifier:@"Header"];

self.collectionView.backgroundColor = [UIColor greenColor];
}
Expand All @@ -43,4 +47,14 @@ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cell
return cell;
}

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
UICollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:PBDCollectionElementKindSectionHeader
withReuseIdentifier:@"Header"
forIndexPath:indexPath];

view.backgroundColor = [UIColor yellowColor];

return view;
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
* Copyright (c) 2016 Pawel Dudek. All rights reserved.
*/
#import <Foundation/Foundation.h>
#import "PBDCarouselCollectionViewLayout.h"
#import "PBDCarouselCollectionViewLayoutPropertiesCache.h"

@class PBDCarouselCollectionViewLayout;

@interface PBDCarouselCollectionViewLayoutHorizontalPropertiesCache : NSObject <PBDCarouselCollectionViewLayoutPropertiesCache>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Copyright (c) 2016 Pawel Dudek. All rights reserved.
*/
#import "PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.h"
#import "PBDCarouselCollectionViewLayout.h"


@interface PBDCarouselCollectionViewLayoutHorizontalPropertiesCache ()
Expand Down Expand Up @@ -54,11 +55,18 @@ - (void)calculateLayoutProperties {
self.cellYPosition = CGRectGetMidY(self.contentRect) - collectionView.contentInset.top;
}

#pragma mark -
#pragma mark - Center Calculation

- (CGPoint)centerForItemAtIndexPath:(NSIndexPath *)indexPath {
CGFloat x = self.contentStart + indexPath.row * (self.layout.itemSize.width + self.layout.interItemSpace) + self.layout.itemSize.width / 2;
return CGPointMake(x, self.cellYPosition);
}

- (CGPoint)centerForHeaderViewAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *firstSectionItem = [NSIndexPath indexPathForItem:0 inSection:indexPath.section];
CGPoint firstItemCenter = [self centerForItemAtIndexPath:firstSectionItem];
firstItemCenter.x -= self.layout.itemSize.width / 2.0f + self.layout.interItemSpace + self.layout.headerSize.width / 2.0f;
return CGPointMake(firstItemCenter.x, self.cellYPosition);
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2016 dudek. All rights reserved.
*/
#import <Foundation/Foundation.h>

@protocol PBDCarouselCollectionViewLayoutPropertiesCache <NSObject>

/*
* Content rect, considering content inset of collection view.
*/
@property(nonatomic, readonly) CGRect contentRect;

/*
* Point on x axis that defines where actual content starts, considering size and content inset of collection view
*/
@property(nonatomic, readonly) CGFloat contentStart;

#pragma mark - Obtaining Item Position

- (CGPoint)centerForItemAtIndexPath:(NSIndexPath *)indexPath;

- (CGPoint)centerForHeaderViewAtIndexPath:(NSIndexPath *)path;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,20 @@

#import <Foundation/Foundation.h>

@protocol PBDCarouselCollectionViewLayoutPropertiesCache <NSObject>

/*
* Content rect, considering content inset of collection view.
*/
@property(nonatomic, readonly) CGRect contentRect;

/*
* Point on x axis that defines where actual content starts, considering size and content inset of collection view
*/
@property(nonatomic, readonly) CGFloat contentStart;

#pragma mark - Obtaining Item Position

- (CGPoint)centerForItemAtIndexPath:(NSIndexPath *)indexPath;

@end
extern NSString *PBDCollectionElementKindSectionHeader;

@interface PBDCarouselCollectionViewLayout : UICollectionViewLayout

@property(nonatomic) CGSize itemSize;

@property(nonatomic) CGFloat interItemSpace;

@property(nonatomic) CGSize headerFooterSize;
/*
* Settings this to non-nil value will enable collection header view. Header view is laid out before first item in collection view.
* It does not participate in centering, aka you cannot center collection view on it.
*
* Defaults to CGSizeZero;
*
*/
@property(nonatomic) CGSize headerSize;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@


#import "PBDCarouselCollectionViewLayout.h"
#import "PBDCarouselCollectionViewLayoutPropertiesCache.h"
#import "PBDCarouselCollectionViewLayoutHorizontalPropertiesCache.h"

NSString *PBDCollectionElementKindSectionHeader = @"PBDCollectionElementKindSectionHeader";

@interface PBDCarouselCollectionViewLayout ()

@property(nonatomic, strong) NSIndexPath *indexPathForCenteredItem;
Expand Down Expand Up @@ -54,6 +57,13 @@ - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
[layoutAttributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
}

UICollectionViewLayoutAttributes *headerLayoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:PBDCollectionElementKindSectionHeader
atIndexPath:[NSIndexPath indexPathForItem:0
inSection:0]];
if (headerLayoutAttributes) {
[layoutAttributes addObject:headerLayoutAttributes];
}

return layoutAttributes;
}

Expand All @@ -69,13 +79,25 @@ - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSInde
return attributes;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes *attributes;
if ([elementKind isEqualToString:PBDCollectionElementKindSectionHeader] && !CGSizeEqualToSize(self.headerSize, CGSizeZero)) {
attributes = [[[self class] layoutAttributesClass] layoutAttributesForSupplementaryViewOfKind:elementKind
withIndexPath:indexPath];
attributes.size = self.headerSize;
attributes.center = [self.propertiesCache centerForHeaderViewAtIndexPath:indexPath];
}

return attributes;
}

#pragma mark - Target Content Offset

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {
CGPoint targetContentOffset = proposedContentOffset;
UICollectionViewLayoutAttributes *layoutAttributesForItemToCenterOn = [self layoutAttributesForUserFingerMovingWithVelocity:velocity
proposedContentOffset:proposedContentOffset];

if (layoutAttributesForItemToCenterOn) {
targetContentOffset.x = layoutAttributesForItemToCenterOn.center.x - self.collectionView.bounds.size.width / 2;
targetContentOffset.y = 0;
Expand Down Expand Up @@ -103,7 +125,9 @@ - (UICollectionViewLayoutAttributes *)layoutAttributesForUserFingerMovingWithVel
UICollectionViewLayoutAttributes *layoutAttributesForItemToCenterOn = nil;
CGRect nextVisibleBounds = [self collectionView].bounds;
nextVisibleBounds.origin = offset;
NSArray *layoutAttributesInRect = [self layoutAttributesForElementsInRect:nextVisibleBounds];

NSPredicate *itemsPredicate = [NSPredicate predicateWithFormat:@"representedElementCategory == %d", UICollectionElementCategoryCell];
NSArray *layoutAttributesInRect = [[self layoutAttributesForElementsInRect:nextVisibleBounds] filteredArrayUsingPredicate:itemsPredicate];

if (velocity.x > 0.0f) {
layoutAttributesForItemToCenterOn = [layoutAttributesInRect lastObject];
Expand Down Expand Up @@ -145,4 +169,11 @@ - (void)setItemSize:(CGSize)itemSize {
}
}

- (void)setHeaderSize:(CGSize)headerSize {
if (!CGSizeEqualToSize(_headerSize, headerSize)) {
_headerSize = headerSize;
[self invalidateLayout];
}
}

@end

0 comments on commit 31d921c

Please sign in to comment.