Skip to content

Commit 9988e46

Browse files
author
Bluelich
committed
support section decoration
1 parent 676d290 commit 9988e46

File tree

4 files changed

+147
-31
lines changed

4 files changed

+147
-31
lines changed

BLCollectionViewTagLayout/Classes/BLCollectionViewTagLayout.h

+25-19
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ typedef NS_ENUM (NSUInteger, BLCollectionViewTagLayoutItemRenderPolicy) {
1616
BLCollectionViewTagLayoutItemRenderCustom = 3,//place item use custom algorithm
1717
};
1818

19+
UIKIT_EXTERN NSString *const BLCollectionElementKindSectionDecoration;
20+
1921
#pragma mark - UICollectionViewTagStyleLayout
2022
#pragma mark -
2123
IB_DESIGNABLE NS_CLASS_AVAILABLE_IOS(8_0)
@@ -24,58 +26,62 @@ IB_DESIGNABLE NS_CLASS_AVAILABLE_IOS(8_0)
2426
* The default size value is (50.0, 50.0).
2527
*/
2628
@property (nonatomic) IBInspectable CGSize itemSize;
27-
/*
29+
/**
2830
* The default value of this property is 10.0.
2931
*/
3032
@property (nonatomic) CGFloat minimumLineSpacing;
31-
/*
33+
/**
3234
* The default value of this property is 10.0.
3335
*/
3436
@property (nonatomic) CGFloat minimumInteritemSpacing;
35-
/*
37+
/**
3638
* The default size values are (0, 0).
3739
*/
3840
@property (nonatomic) CGSize headerReferenceSize;
39-
/*
41+
/**
4042
* The default size values are (0, 0).
4143
*/
4244
@property (nonatomic) CGSize footerReferenceSize;
43-
/*
45+
/**
4446
* The default edge insets are all set to 0.
4547
*
46-
* It does not affect header footer,but for section items similar as UICollectionViewFlowLayout.
48+
* It does not affect header footer,but for section items. Similar as UICollectionViewFlowLayout.
4749
*/
4850
@property (nonatomic) UIEdgeInsets sectionInset;
49-
/*
50-
* The default value is CGFLOAT_MAX
51-
*
52-
* You can specify the value for section items height limitation.
53-
*
54-
* Note : This value is the height of the section elements,except the header footer and section inset.
55-
*/
51+
/**
52+
* The default value is CGFLOAT_MAX
53+
*
54+
* You can specify the value for section items height limitation.
55+
*
56+
* Note : This value is the height of the section elements,except the header footer and section inset.
57+
*/
5658
@property (nonatomic) CGFloat maximumSectionHeight;
57-
/*
59+
/**
5860
* The default is UICollectionViewScrollDirectionVertical.
5961
*
6062
* Note: UICollectionViewScrollDirectionHorizontal is unimplemented.
6163
*/
6264
@property (nonatomic) UICollectionViewScrollDirection scrollDirection;
63-
/*
65+
/**
6466
* The default is BLCollectionViewTagLayoutItemRenderDefault.
6567
*/
6668
@property (nonatomic) BLCollectionViewTagLayoutItemRenderPolicy itemRenderPolicy;
67-
/*
69+
/**
6870
* The default value of this property is NO.
6971
*/
7072
@property (nonatomic) BOOL sectionHeadersPinToVisibleBounds;
71-
/*
73+
/**
7274
* The default value of this property is NO.
7375
*/
7476
@property (nonatomic) BOOL sectionFootersPinToVisibleBounds;
77+
/**
78+
* The default value of this property is NO.
79+
*/
80+
@property (nonatomic) BOOL sectionDecorationVisiable;
7581
@end
7682

7783
@interface BLCollectionViewTagLayout (UICollectionViewContentInsetAdjustment)
78-
/*
84+
/**
7985
* Additional adjusted contentInset by system
8086
*
8187
* As usual, you don't need to care about this,the layout will fill in it automatically.
@@ -92,7 +98,7 @@ IB_DESIGNABLE NS_CLASS_AVAILABLE_IOS(8_0)
9298
*/
9399
@property (nonatomic,assign) UIEdgeInsets systemAdditionalAdjustedContentInset;
94100

95-
/*
101+
/**
96102
* Automatically systemAdditionalAdjustedContentInset configuration
97103
* by frame and translucent of UINavigationBar and UITabBar (and status bar)
98104
*

BLCollectionViewTagLayout/Classes/BLCollectionViewTagLayout.m

+57-5
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,34 @@
77

88
#import "BLCollectionViewTagLayout.h"
99

10+
NSString *const BLCollectionElementKindSectionDecoration = @"BLCollectionElementKindSectionDecoration";
11+
1012
#pragma mark - UICollectionViewTagStyleLayoutSectionAttributes Declare
1113
#pragma mark -
1214
@interface UICollectionViewTagStyleLayoutSectionAttributes : NSObject<NSCopying>
1315
@property (nonatomic,strong) UICollectionViewLayoutAttributes *header;
1416
@property (nonatomic,strong) NSArray<UICollectionViewLayoutAttributes *> *items;
1517
@property (nonatomic,strong) UICollectionViewLayoutAttributes *footer;
18+
@property (nonatomic,strong) UICollectionViewLayoutAttributes *decoration;
1619
+ (instancetype)layoutAttributesWithHeader:(UICollectionViewLayoutAttributes *)header
1720
items:(NSArray<UICollectionViewLayoutAttributes *> *)items
18-
footer:(UICollectionViewLayoutAttributes *)footer;
21+
footer:(UICollectionViewLayoutAttributes *)footer
22+
decoration:(UICollectionViewLayoutAttributes *)decoration;
1923
@end
2024
#pragma mark - UICollectionViewTagStyleLayoutSectionAttributes Implementation
2125
#pragma mark -
2226
@implementation UICollectionViewTagStyleLayoutSectionAttributes
2327
+ (instancetype)layoutAttributesWithHeader:(UICollectionViewLayoutAttributes *)header
2428
items:(NSArray<UICollectionViewLayoutAttributes *> *)items
2529
footer:(UICollectionViewLayoutAttributes *)footer
30+
decoration:(UICollectionViewLayoutAttributes *)decoration
2631
{
2732
UICollectionViewTagStyleLayoutSectionAttributes *obj =
2833
UICollectionViewTagStyleLayoutSectionAttributes.new;
2934
obj.header = header;
3035
obj.items = items;
3136
obj.footer = footer;
37+
obj.decoration = decoration;
3238
return obj;
3339
}
3440
- (id)copyWithZone:(NSZone *)zone
@@ -38,6 +44,7 @@ - (id)copyWithZone:(NSZone *)zone
3844
obj.header = self.header.copy;
3945
obj.items = [[NSArray alloc] initWithArray:self.items copyItems:YES];
4046
obj.footer = self.footer.copy;
47+
obj.decoration = self.decoration.copy;
4148
return obj;
4249
}
4350
@end
@@ -213,9 +220,22 @@ - (void)setup
213220
_itemRenderPolicy = BLCollectionViewTagLayoutItemRenderDefault;
214221
_sectionHeadersPinToVisibleBounds = NO;
215222
_sectionFootersPinToVisibleBounds = NO;
223+
_sectionDecorationVisiable = NO;
216224
_invalidatedForPinSectionHeaderFootersToVisibleBounds = NO;
217225
_additionalAdjustedContentInset = UIEdgeInsetsZero;
218226
}
227+
- (void)registerNib:(UINib *)nib forDecorationViewOfKind:(NSString *)elementKind
228+
{
229+
NSAssert([elementKind isEqualToString:BLCollectionElementKindSectionDecoration],@"Kind of %@ current unsupported",elementKind);
230+
if (![elementKind isEqualToString:BLCollectionElementKindSectionDecoration]) return;
231+
[super registerNib:nib forDecorationViewOfKind:elementKind];
232+
}
233+
- (void)registerClass:(Class)viewClass forDecorationViewOfKind:(NSString *)elementKind
234+
{
235+
NSAssert([elementKind isEqualToString:BLCollectionElementKindSectionDecoration],@"Kind of %@ current unsupported",elementKind);
236+
if (![elementKind isEqualToString:BLCollectionElementKindSectionDecoration]) return;
237+
[super registerClass:viewClass forDecorationViewOfKind:elementKind];
238+
}
219239
- (void)invalidateLayoutWithContext:(UICollectionViewLayoutInvalidationContext *)context
220240
{
221241
[super invalidateLayoutWithContext:context];
@@ -285,6 +305,12 @@ - (void)setSectionFootersPinToVisibleBounds:(BOOL)sectionFootersPinToVisibleBoun
285305
_sectionFootersPinToVisibleBounds = sectionFootersPinToVisibleBounds;
286306
[self invalidateLayout];
287307
}
308+
- (void)setSectionDecorationVisiable:(BOOL)sectionDecorationVisiable
309+
{
310+
if (_sectionDecorationVisiable == sectionDecorationVisiable) return;
311+
_sectionDecorationVisiable = sectionDecorationVisiable;
312+
[self invalidateLayout];
313+
}
288314
#pragma mark -
289315
- (id<BLCollectionViewDelegateTagStyleLayout>)delegate
290316
{
@@ -311,6 +337,11 @@ - (NSInteger)zIndexForHeaderFooter
311337
if (CGRectIntersectsRect(rect, obj.footer.frame) && obj.footer.frame.size.height > 0) {
312338
[layoutAttributes addObject:obj.footer];
313339
}
340+
if (self.sectionDecorationVisiable) {
341+
if (CGRectIntersectsRect(rect, obj.decoration.frame) && obj.decoration.frame.size.height > 0) {
342+
[layoutAttributes addObject:obj.decoration];
343+
}
344+
}
314345
}
315346
return layoutAttributes.copy;
316347
}
@@ -409,7 +440,13 @@ - (void)setupLayoutAttributes
409440
attributesForFooter.frame = CGRectMake(0, maxY, maxContentWidth, footerReferenceSize.height);
410441
attributesForFooter.zIndex = self.zIndexForHeaderFooter;
411442

412-
[self.originSectionAttributes addObject:[UICollectionViewTagStyleLayoutSectionAttributes layoutAttributesWithHeader:attributesForHeader items:sortedAttributesForItems footer:attributesForFooter]];
443+
//section decoration
444+
UICollectionViewLayoutAttributes *attrubuteForDecoration = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:BLCollectionElementKindSectionDecoration withIndexPath:indexPathForHeaderFooter];
445+
attrubuteForDecoration.frame = CGRectMake(-sectionInset.left, CGRectGetMinY(attributesForHeader.frame), maxContentWidth + sectionInset.left + sectionInset.right, CGRectGetMaxY(attributesForFooter.frame) - CGRectGetMinY(attributesForHeader.frame));
446+
attrubuteForDecoration.zIndex = -self.zIndexForHeaderFooter;
447+
448+
//
449+
[self.originSectionAttributes addObject:[UICollectionViewTagStyleLayoutSectionAttributes layoutAttributesWithHeader:attributesForHeader items:sortedAttributesForItems footer:attributesForFooter decoration:attrubuteForDecoration]];
413450

414451
maxY = CGRectGetMaxY(attributesForFooter.frame);
415452
}
@@ -436,12 +473,12 @@ - (void)updateAttributesForPinSectionHeaderFootersToVisibleBounds:(CGRect)newBou
436473
visibleRectForPinHeaderFooter.origin.y += topOffset;
437474
visibleRectForPinHeaderFooter.size.height -= topOffset;
438475
visibleRectForPinHeaderFooter.size.height -= bottomOffset;
439-
// copy items
440-
self.sectionAttributes = [[NSMutableArray alloc] initWithArray:self.originSectionAttributes copyItems:YES];
441476
if (self.collectionViewContentSize.height <= CGRectGetHeight(visibleRectForPinHeaderFooter)) {
442477
//does no need to pin header or footer to visible bounds any more.
443478
return;
444479
}
480+
// copy items
481+
self.sectionAttributes = [[NSMutableArray alloc] initWithArray:self.originSectionAttributes copyItems:YES];
445482
NSArray<UICollectionViewLayoutAttributes *> *attributes = [self layoutAttributesForElementsInRect:visibleRectForPinHeaderFooter sectionAttributes:self.originSectionAttributes];
446483
if (sectionHeadersShouldPinToVisibleBounds) {
447484
UICollectionViewLayoutAttributes *header =
@@ -539,7 +576,13 @@ - (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind
539576
}
540577
- (UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString*)elementKind atIndexPath:(NSIndexPath *)indexPath
541578
{
542-
return [super layoutAttributesForDecorationViewOfKind:elementKind atIndexPath:indexPath];
579+
if (indexPath.section >= self.sectionAttributes.count) return nil;
580+
UICollectionViewTagStyleLayoutSectionAttributes *sectionAttributes = self.sectionAttributes[indexPath.section];
581+
if (elementKind == BLCollectionElementKindSectionDecoration) {
582+
return sectionAttributes.decoration;
583+
}else{
584+
return [super layoutAttributesForDecorationViewOfKind:elementKind atIndexPath:indexPath];
585+
}
543586
}
544587
#pragma mark -
545588
- (UICollectionViewLayoutInvalidationContext *)invalidationContextForBoundsChange:(CGRect)newBounds
@@ -615,6 +658,7 @@ @interface BLCollectionViewTagLayout (IBDESIGNABLE)
615658
@property (nonatomic) IBInspectable CGSize footerSize;
616659
@property (nonatomic) IBInspectable BOOL pinHeaders;
617660
@property (nonatomic) IBInspectable BOOL pinFooters;
661+
@property (nonatomic) IBInspectable BOOL useDecoration;
618662
@end
619663

620664
@implementation BLCollectionViewTagLayout (IBDESIGNABLE)
@@ -714,6 +758,14 @@ - (BOOL)pinFooters
714758
{
715759
return self.sectionFootersPinToVisibleBounds;
716760
}
761+
- (void)setUseDecoration:(BOOL)useDecoration
762+
{
763+
self.sectionDecorationVisiable = useDecoration;
764+
}
765+
- (BOOL)useDecoration
766+
{
767+
return self.sectionDecorationVisiable;;
768+
}
717769
- (void)setRenderType:(NSInteger)renderType
718770
{
719771
self.itemRenderPolicy = renderType;

Example/BLCollectionViewTagLayout/BLViewController.m

+48-1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,39 @@ - (void)swizzling_setContentSize:(CGSize)contentSize
7575
}
7676
@end
7777

78+
@interface BLDecorationView : UICollectionReusableView
79+
@end
80+
@implementation BLDecorationView
81+
- (instancetype)initWithFrame:(CGRect)frame
82+
{
83+
self = [super initWithFrame:frame];
84+
if (self) {
85+
self.backgroundColor = UIColor.blueColor;
86+
self.layer.cornerRadius = 5;
87+
self.clipsToBounds = YES;
88+
UIButton *obj = UIButton.new;
89+
[self addSubview:obj];
90+
obj.translatesAutoresizingMaskIntoConstraints = NO;
91+
[obj.centerXAnchor constraintEqualToAnchor:self.centerXAnchor].active = YES;
92+
[obj.centerYAnchor constraintEqualToAnchor:self.centerYAnchor].active = YES;
93+
[obj.widthAnchor constraintEqualToAnchor:self.widthAnchor].active = YES;
94+
[obj.heightAnchor constraintEqualToAnchor:self.heightAnchor].active = YES;
95+
[obj addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
96+
}
97+
return self;
98+
}
99+
- (void)buttonClicked:(UIButton *)sender
100+
{
101+
sender.backgroundColor = [UIColor colorWithHue:0.5 saturation:0.5 brightness:arc4random()%256/255.f alpha:1];
102+
}
103+
- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
104+
{
105+
[super applyLayoutAttributes:layoutAttributes];
106+
self.backgroundColor = layoutAttributes.indexPath.section % 2 ? UIColor.redColor : UIColor.blueColor;
107+
self.layer.zPosition = -1;
108+
}
109+
@end
110+
78111
@interface BLViewController ()<BLCollectionViewDelegateTagStyleLayout>
79112
@property (nonatomic,strong) NSArray<NSString *> *alphabetArray;
80113
@property (nonatomic,strong) NSMutableArray<NSMutableArray *> *dataSource;
@@ -89,7 +122,7 @@ - (void)viewDidLoad {
89122

90123
self.collectionView.contentInset = UIEdgeInsetsMake(44, 44, 44, 44);
91124
// self.collectionView.scrollIndicatorInsets = UIEdgeInsetsMake(14, 0, 14, 0);
92-
125+
[self.blCollectionViewLayout registerClass:BLDecorationView.class forDecorationViewOfKind:BLCollectionElementKindSectionDecoration];
93126
[self.blCollectionViewLayout
94127
autoConfigSystemAdditionalAdjustedContentInsetWith:UIApplication.sharedApplication.statusBarFrame
95128
navigationBar:self.navigationController.navigationBar
@@ -140,6 +173,7 @@ - (UINavigationBar *)navigationBar
140173
];
141174
item.rightBarButtonItems =
142175
@[
176+
[[UIBarButtonItem alloc] initWithTitle:@"Decoration" style:UIBarButtonItemStyleDone target:self action:@selector(showDecoration:)],
143177
[[UIBarButtonItem alloc] initWithTitle:@"UnPin" style:UIBarButtonItemStyleDone target:self action:@selector(unPin:)],
144178
[[UIBarButtonItem alloc] initWithTitle:@"Pin" style:UIBarButtonItemStyleDone target:self action:@selector(pin:)]
145179
];
@@ -200,6 +234,16 @@ - (IBAction)unPin:(UIBarButtonItem *)sender
200234
self.blCollectionViewLayout.sectionHeadersPinToVisibleBounds = NO;
201235
self.blCollectionViewLayout.sectionFootersPinToVisibleBounds = NO;
202236
}
237+
- (IBAction)showDecoration:(UIBarButtonItem *)sender
238+
{
239+
self.blCollectionViewLayout.sectionDecorationVisiable =
240+
!self.blCollectionViewLayout.sectionDecorationVisiable;
241+
if (self.blCollectionViewLayout.sectionDecorationVisiable) {
242+
sender.title = @"Decoration";
243+
}else{
244+
sender.title = @"No Decoration";
245+
}
246+
}
203247
- (IBAction)add:(UIBarButtonItem *)sender
204248
{
205249
if (arc4random() % 2) {
@@ -242,6 +286,9 @@ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cell
242286
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
243287
{
244288
UICollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:kind forIndexPath:indexPath];
289+
if (kind == BLCollectionElementKindSectionDecoration) {
290+
return view;
291+
}
245292
UILabel *label = view.subviews.firstObject;
246293
if (!label) {
247294
label = UILabel.new;

0 commit comments

Comments
 (0)