Skip to content

Commit b7ea95d

Browse files
author
Brian Dorfman
committed
Merge pull request #5 from foursquare/section-headers
Adds support for pinned section headers
2 parents 94e3033 + 3749c36 commit b7ea95d

File tree

4 files changed

+380
-220
lines changed

4 files changed

+380
-220
lines changed

FSQAlignedLayoutExample/FSQAlignedLayoutExample/FSQAlignedIndentExampleViewController.m

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
@interface FSQExampleSectionData : NSObject
1414
@property (nonatomic) FSQCollectionViewHorizontalAlignment hAlignment;
15+
@property (nonatomic) NSString *headerString;
1516
@property (nonatomic) NSArray *cellData;
1617
@end
1718

@@ -27,6 +28,28 @@ @interface FSQExampleCellData : NSObject
2728
@implementation FSQExampleCellData
2829
@end
2930

31+
@interface FSQExampleHeaderView : UICollectionReusableView
32+
@property (nonatomic) UILabel *label;
33+
@end
34+
35+
@implementation FSQExampleHeaderView
36+
37+
- (instancetype)initWithFrame:(CGRect)frame {
38+
if ((self = [super initWithFrame:frame])) {
39+
self.backgroundColor = [UIColor colorWithWhite:0.96f alpha:1.0f];
40+
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(15.0f, 0, frame.size.width - 30.0f, frame.size.height)];
41+
label.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
42+
label.backgroundColor = [UIColor clearColor];
43+
label.font = kMainFont;
44+
label.numberOfLines = 1;
45+
[self addSubview:label];
46+
self.label = label;
47+
}
48+
return self;
49+
}
50+
51+
@end
52+
3053
@interface FSQExampleCell : UICollectionViewCell
3154
@property (nonatomic) UILabel *label;
3255
@end
@@ -72,7 +95,9 @@ - (void)viewDidLoad {
7295
[super viewDidLoad];
7396
self.view.backgroundColor = [UIColor whiteColor];
7497
self.collectionView.backgroundColor = [UIColor whiteColor];
98+
self.collectionView.alwaysBounceVertical = YES;
7599
[self.collectionView registerClass:[FSQExampleCell class] forCellWithReuseIdentifier:@"cell"];
100+
[self.collectionView registerClass:[FSQExampleHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header"];
76101

77102
CGRect frame = self.collectionView.frame;
78103
frame.origin.y += 20;
@@ -136,6 +161,22 @@ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
136161
return cell;
137162
}
138163

164+
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceHeightForHeaderInSection:(NSInteger)section {
165+
FSQExampleSectionData *sectionData = self.sectionData[section];
166+
return (sectionData.headerString.length > 0) ? 30.0f : 0.0f;
167+
}
168+
169+
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
170+
UICollectionReusableView *view = nil;
171+
if (kind == UICollectionElementKindSectionHeader) {
172+
FSQExampleSectionData *sectionData = self.sectionData[indexPath.section];
173+
FSQExampleHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"header" forIndexPath:indexPath];
174+
headerView.label.text = sectionData.headerString;
175+
view = headerView;
176+
}
177+
return view;
178+
}
179+
139180
- (NSArray *)generateExampleData {
140181
// First section
141182
FSQExampleSectionData *sectionOne = [FSQExampleSectionData new];
@@ -148,6 +189,7 @@ - (NSArray *)generateExampleData {
148189
// Second section
149190
FSQExampleSectionData *sectionTwo = [FSQExampleSectionData new];
150191
sectionTwo.hAlignment = FSQCollectionViewHorizontalAlignmentLeft;
192+
sectionTwo.headerString = @"Paul";
151193

152194
FSQExampleCellData *sectionTwoAvatarCell = [FSQExampleCellData new];
153195
sectionTwoAvatarCell.backgroundColor = [UIColor redColor];
@@ -170,6 +212,7 @@ - (NSArray *)generateExampleData {
170212
// Third Section
171213
FSQExampleSectionData *sectionThree = [FSQExampleSectionData new];
172214
sectionThree.hAlignment = FSQCollectionViewHorizontalAlignmentLeft;
215+
sectionThree.headerString = @"Jessica";
173216

174217
FSQExampleCellData *sectionThreeAvatarCell = [FSQExampleCellData new];
175218
sectionThreeAvatarCell.backgroundColor = [UIColor blueColor];

FSQCollectionViewAlignedLayout.h

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
Overview:
99
1010
FSQCollectionViewAlignedLayout lays out collection view cells sort of like how a type setter would draw out a string,
11-
but with collection cells instead of font glyphs. Each section can have both a vertical and horizontal alignment
12-
(horizontal aligns each line relative to the whole section, vertical aligns the items within each line if they are
11+
but with collection cells instead of font glyphs. Each section can have both a vertical and horizontal alignment
12+
(horizontal aligns each line relative to the whole section, vertical aligns the items within each line if they are
1313
different heights). It also allows you to specify distance between items in each section and between lines.
1414
15-
Each cell can have not only a size, but insets. You can also tell it to insert "line breaks" before or
15+
Each cell can have not only a size, but insets. You can also tell it to insert "line breaks" before or
1616
after each cell to get things to wrap how you want.
1717
1818
You can set defaults for section and cell styles just like you can in Flow Layout. Or you can implement delegate methods:
@@ -23,7 +23,7 @@
2323
2424
- (FSQCollectionViewAlignedLayoutCellAttributes*)collectionView:layout:attributesForCellAtIndexPath:
2525
26-
To return cell layout information for the specified indexPath.
26+
To return cell layout information for the specified indexPath.
2727
2828
- (CGSize)collectionView:layout:sizeForItemAtIndexPath:remainingLineSpace:
2929
@@ -39,6 +39,12 @@
3939

4040
@class FSQCollectionViewAlignedLayoutSectionAttributes, FSQCollectionViewAlignedLayoutCellAttributes;
4141

42+
@interface FSQCollectionViewAlignedLayoutInvalidationContext : UICollectionViewLayoutInvalidationContext
43+
44+
@property (nonatomic) BOOL invalidateAlignedLayoutAttributes; // if set to NO, aligned layout will keep all layout information, effectively not invalidating - useful for a subclass which invalidates only a piece of itself
45+
46+
@end
47+
4248
@interface FSQCollectionViewAlignedLayout : UICollectionViewLayout <NSFastEnumeration>
4349

4450
/**
@@ -48,11 +54,11 @@
4854
*/
4955
@property (nonatomic) IBInspectable CGSize defaultCellSize;
5056

51-
/**
57+
/**
5258
Used if attributesForSectionAtIndex delegate method is not implemented
5359
5460
Defaults to [FSQCollectionViewAlignedLayoutSectionAttributes topLeftAlignment] if not set.
55-
*/
61+
*/
5662
@property (nonatomic) FSQCollectionViewAlignedLayoutSectionAttributes *defaultSectionAttributes;
5763

5864
/**
@@ -62,14 +68,14 @@
6268
*/
6369
@property (nonatomic) FSQCollectionViewAlignedLayoutCellAttributes *defaultCellAttributes;
6470

65-
/**
71+
/**
6672
Space in points between the bottom most part of a section and the top most part of the next one.
6773
6874
Defaults to 10 if not set.
6975
*/
7076
@property (nonatomic) IBInspectable CGFloat sectionSpacing;
7177

72-
/**
78+
/**
7379
Insets in points around the entire contents of the collection. Defaults to (5, 5, 5, 5) if not set
7480
*/
7581
@property (nonatomic) UIEdgeInsets contentInsets;
@@ -88,7 +94,7 @@
8894
@param indexPath The index path of the item.
8995
@param remainingLineSpace The amount of space in pts remaining on the line the layout is currently laying out.
9096
91-
@return The size the cell should be. If you return a size whose width is less than or equal to @c remainingLineSpace
97+
@return The size the cell should be. If you return a size whose width is less than or equal to @c remainingLineSpace
9298
it will be laid out on the same lane.
9399
94100
@note remainingLineSpace takes into account any insets that may exist for the current cell, subtracting the
@@ -99,6 +105,18 @@
99105
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
100106
remainingLineSpace:(CGFloat)remainingLineSpace;
101107

108+
/**
109+
* Asks the delegate for the height of the header view in the specified section.
110+
* If you do not implement this method, or the height returned is 0, no header is added.
111+
*
112+
* @param collectionView The collection view object displaying the layout.
113+
* @param collectionViewLayout The layout object requesting the information.
114+
* @param section The index of the section whose header size is being requested.
115+
*
116+
* @return The height of the header. If you return a value of 0, no header is added.
117+
*/
118+
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceHeightForHeaderInSection:(NSInteger)section;
119+
102120
/**
103121
Used instead of defaultSectionAttributes if implemented.
104122
@@ -223,16 +241,16 @@ typedef NS_ENUM(NSInteger, FSQCollectionViewVerticalAlignment) {
223241
*/
224242
@interface FSQCollectionViewAlignedLayoutCellAttributes : NSObject
225243

226-
/**
227-
Insets will be added to size for layout purposes, but the collection cell will end up actually being the size reported
244+
/**
245+
Insets will be added to size for layout purposes, but the collection cell will end up actually being the size reported
228246
in either the sizeForItemAtIndexPath or the layout's defaultCellSize property.
229247
230-
You can add more padding around cells with positive insets,
248+
You can add more padding around cells with positive insets,
231249
or effectively shrink cell/line spacing or make cells overlap by using negative insets.
232250
*/
233251
@property (nonatomic, readonly) UIEdgeInsets insets;
234252

235-
/**
253+
/**
236254
If YES, ensures this cell is the first thing on the line by inserting a line break before if necessary
237255
238256
If there was going to be a line break before anyway, this has no effect (does not insert an EXTRA newline)
@@ -249,20 +267,20 @@ typedef NS_ENUM(NSInteger, FSQCollectionViewVerticalAlignment) {
249267
/**
250268
If YES and section alignment is Left or Right, future lines will start from this cell's left or right edge respectively.
251269
252-
The available width of all future lines will be lowered and padding will be added to the appropriate side to inset
270+
The available width of all future lines will be lowered and padding will be added to the appropriate side to inset
253271
future lines
254272
255-
@note There is no way to stop indenting once you start it without creating a new section, although you can start a new
273+
@note There is no way to stop indenting once you start it without creating a new section, although you can start a new
256274
indentation from a different cell.
257275
258-
@note The alignment is from the actual position of the cell, not including its insets. Therefore you can fake an
276+
@note The alignment is from the actual position of the cell, not including its insets. Therefore you can fake an
259277
"unindentation" by using negative insets and then starting a new indentation.
260278
*/
261279
@property (nonatomic, readonly) BOOL startLineIndentation;
262280

263-
/**
264-
Reusable shared pointer to a simple cell attribute object.
265-
Zero insets, no line breaks, no indentation.
281+
/**
282+
Reusable shared pointer to a simple cell attribute object.
283+
Zero insets, no line breaks, no indentation.
266284
*/
267285
+ (FSQCollectionViewAlignedLayoutCellAttributes *)defaultCellAttributes;
268286

@@ -281,4 +299,4 @@ typedef NS_ENUM(NSInteger, FSQCollectionViewVerticalAlignment) {
281299
shouldEndLine:(BOOL)shouldEndLine
282300
startLineIndentation:(BOOL)startLineIndentation;
283301

284-
@end
302+
@end

0 commit comments

Comments
 (0)