This commit is contained in:
启星
2025-08-12 14:27:12 +08:00
parent 9d18b353b1
commit 1bd5e77c45
8785 changed files with 978163 additions and 2 deletions

View File

@@ -0,0 +1,25 @@
//
// ZLBaseEventModel.h
// ZLCollectionView
//
// Created by hqtech on 2020/4/18.
// Copyright © 2020 zhaoliang chen. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface ZLBaseEventModel : NSObject
@property(nonatomic,copy)NSString* _Nullable eventName;
@property(nonatomic,strong)id _Nullable parameter;
- (instancetype)initWithEventName:(NSString* _Nullable)eventName;
- (instancetype)initWithEventName:(NSString* _Nullable)eventName parameter:(id _Nullable)parameter;
+ (instancetype)createWithEventName:(NSString* _Nullable)eventName;
+ (instancetype)createWithEventName:(NSString* _Nullable)eventName parameter:(id _Nullable)parameter;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,35 @@
//
// ZLBaseEventModel.m
// ZLCollectionView
//
// Created by hqtech on 2020/4/18.
// Copyright © 2020 zhaoliang chen. All rights reserved.
//
#import "ZLBaseEventModel.h"
@implementation ZLBaseEventModel
- (instancetype)initWithEventName:(NSString* _Nullable)eventName {
return [self initWithEventName:eventName parameter:nil];
}
- (instancetype)initWithEventName:(NSString* _Nullable)eventName parameter:(id _Nullable)parameter {
if (self == [super init]) {
self.eventName = eventName;
self.parameter = parameter;
}
return self;
}
+ (instancetype)createWithEventName:(NSString* _Nullable)eventName {
ZLBaseEventModel* eventModel = [[ZLBaseEventModel alloc]initWithEventName:eventName parameter:nil];
return eventModel;
}
+ (instancetype)createWithEventName:(NSString* _Nullable)eventName parameter:(id _Nullable)parameter {
ZLBaseEventModel* eventModel = [[ZLBaseEventModel alloc]initWithEventName:eventName parameter:parameter];
return eventModel;
}
@end

View File

@@ -0,0 +1,25 @@
//
// ZLCellFakeView.h
// ZLCollectionView
//
// Created by zhaoliang chen on 2018/7/25.
// Copyright © 2018年 zhaoliang chen. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ZLCellFakeView : UIView
@property (nonatomic, weak)UICollectionViewCell *cell;
@property (nonatomic, strong)UIImageView *cellFakeImageView;
@property (nonatomic, strong)UIImageView *cellFakeHightedView;
@property (nonatomic, strong)NSIndexPath *indexPath;
@property (nonatomic, assign)CGPoint originalCenter;
@property (nonatomic, assign)CGRect cellFrame;
- (instancetype)initWithCell:(UICollectionViewCell *)cell;
- (void)changeBoundsIfNeeded:(CGRect)bounds;
- (void)pushFowardView;
- (void)pushBackView:(void(^)(void))completion;
@end

View File

@@ -0,0 +1,100 @@
//
// ZLCellFakeView.m
// ZLCollectionView
//
// Created by zhaoliang chen on 2018/7/25.
// Copyright © 2018 zhaoliang chen. All rights reserved.
//
#import "ZLCellFakeView.h"
@implementation ZLCellFakeView
- (instancetype)initWithCell:(UICollectionViewCell *)cell{
self = [super initWithFrame:cell.frame];
if (self) {
self.cell = cell;
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOffset = CGSizeMake(0, 0);
self.layer.shadowOpacity = 0;
self.layer.shadowRadius = 5.0;
self.layer.shouldRasterize = false;
self.layer.masksToBounds = YES;
self.clipsToBounds = YES;
self.cellFakeImageView = [[UIImageView alloc]initWithFrame:self.bounds];
self.cellFakeImageView.contentMode = UIViewContentModeScaleAspectFill;
self.cellFakeImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.cellFakeHightedView = [[UIImageView alloc]initWithFrame:self.bounds];
self.cellFakeHightedView.contentMode = UIViewContentModeScaleAspectFill;
self.cellFakeHightedView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
cell.highlighted = YES;
self.cellFakeHightedView.image = [self getCellImage];
cell.highlighted = NO;
self.cellFakeImageView.image = [self getCellImage];
[self addSubview:self.cellFakeImageView];
[self addSubview:self.cellFakeHightedView];
}
return self;
}
- (void)changeBoundsIfNeeded:(CGRect)bounds{
if (CGRectEqualToRect(self.bounds, bounds)) {
return;
}
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionBeginFromCurrentState animations:^{
self.bounds = bounds;
} completion:nil];
}
- (void)pushFowardView{
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionBeginFromCurrentState animations:^{
self.center = self.originalCenter;
self.transform = CGAffineTransformMakeScale(1.1, 1.1);
self.cellFakeHightedView.alpha = 0;
CABasicAnimation *shadowAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
shadowAnimation.fromValue = @(0);
shadowAnimation.toValue = @(0.7);
shadowAnimation.removedOnCompletion = NO;
shadowAnimation.fillMode = kCAFillModeForwards;
[self.layer addAnimation:shadowAnimation forKey:@"applyShadow"];
} completion:^(BOOL finished) {
[self.cellFakeHightedView removeFromSuperview];
}];
}
- (void)pushBackView:(void(^)(void))completion{
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionBeginFromCurrentState animations:^{
//self.transform = CGAffineTransformIdentity;
//self.frame = self.cellFrame;
CABasicAnimation *shadowAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
shadowAnimation.fromValue = @(0.7);
shadowAnimation.toValue = @(0);
shadowAnimation.removedOnCompletion = NO;
shadowAnimation.fillMode = kCAFillModeForwards;
[self.layer addAnimation:shadowAnimation forKey:@"removeShadow"];
} completion:^(BOOL finished) {
if (completion) {
completion();
}
}];
}
- (UIImage *)getCellImage{
UIGraphicsBeginImageContextWithOptions(_cell.bounds.size, NO, [UIScreen mainScreen].scale * 2);
[self.cell.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
@end

View File

@@ -0,0 +1,17 @@
//
// ZLCollectionBackView.h
// ZLCollectionView
//
// Created by zhaoliang chen on 2020/4/17.
// Copyright © 2020 zhaoliang chen. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface ZLCollectionBaseDecorationView : UICollectionReusableView
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,46 @@
//
// ZLCollectionBackView.m
// ZLCollectionView
//
// Created by zhaoliang chen on 2020/4/17.
// Copyright © 2020 zhaoliang chen. All rights reserved.
//
#import "ZLCollectionBaseDecorationView.h"
#import "ZLCollectionViewBackgroundViewLayoutAttributes.h"
#import <objc/runtime.h>
@implementation ZLCollectionBaseDecorationView
- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
//
ZLCollectionViewBackgroundViewLayoutAttributes *myLayoutAttributes = (ZLCollectionViewBackgroundViewLayoutAttributes*)layoutAttributes;
unsigned int methodCount = 0;
Method *methods = class_copyMethodList([self class], &methodCount);
if ([myLayoutAttributes isKindOfClass:[ZLCollectionViewBackgroundViewLayoutAttributes class]] && myLayoutAttributes.eventName != nil && myLayoutAttributes.eventName.length > 0) {
for(int i = 0; i < methodCount; i++) {
Method method = methods[i];
SEL sel = method_getName(method);
const char *name = sel_getName(sel);
NSString* methodName = [NSString stringWithUTF8String:name];
if ([methodName isEqualToString:myLayoutAttributes.eventName]) {
//object_setClass(self, newClass);
SEL selector = NSSelectorFromString(myLayoutAttributes.eventName);
IMP imp = [self methodForSelector:selector];
if ([self respondsToSelector:selector]) {
if (myLayoutAttributes.parameter) {
void (*func) (id, SEL, id) = (void *)imp;
func(self,selector,myLayoutAttributes.parameter);
} else {
void (*func) (id, SEL) = (void *)imp;
func(self,selector);
}
}
break;
};
}
}
free(methods);
}
@end

View File

@@ -0,0 +1,13 @@
//
// ZLCollectionReusableView.h
// ZLCollectionView
//
// Created by zhaoliang chen on 2018/7/9.
// Copyright © 2018年 zhaoliang chen. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ZLCollectionReusableView : UICollectionReusableView
@end

View File

@@ -0,0 +1,57 @@
//
// ZLCollectionReusableView.m
// ZLCollectionView
//
// Created by zhaoliang chen on 2018/7/9.
// Copyright © 2018 zhaoliang chen. All rights reserved.
//
#import "ZLCollectionReusableView.h"
#import "ZLCollectionViewLayoutAttributes.h"
@interface ZLCollectionReusableView ()
@property(nonatomic,strong)UIImageView* ivBackground;
@end
@implementation ZLCollectionReusableView
- (instancetype)initWithFrame:(CGRect)frame {
if (self == [super initWithFrame:frame]) {
self.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:self.ivBackground];
self.ivBackground.translatesAutoresizingMaskIntoConstraints = NO;
[self addConstraints:@[
[NSLayoutConstraint constraintWithItem:self.ivBackground attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0],
[NSLayoutConstraint constraintWithItem:self.ivBackground attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0 constant: 0.0],
[NSLayoutConstraint constraintWithItem:self.ivBackground attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant: 0.0],
[NSLayoutConstraint constraintWithItem:self.ivBackground attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant: 0.0]
]];
}
return self;
}
- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
[super applyLayoutAttributes:layoutAttributes];
//
ZLCollectionViewLayoutAttributes *ecLayoutAttributes = (ZLCollectionViewLayoutAttributes*)layoutAttributes;
if (ecLayoutAttributes.color) {
self.backgroundColor = ecLayoutAttributes.color;
}
if (ecLayoutAttributes.image) {
self.ivBackground.image = ecLayoutAttributes.image;
}
}
- (UIImageView*)ivBackground {
if (!_ivBackground) {
_ivBackground = [[UIImageView alloc]init];
_ivBackground.contentMode = UIViewContentModeScaleAspectFill;
_ivBackground.backgroundColor = [UIColor clearColor];
}
return _ivBackground;
}
@end

View File

@@ -0,0 +1,27 @@
//
// ZLCollectionViewBackViewLayoutAttributes.h
// ZLCollectionView
//
// Created by zhaoliang chen on 2020/4/17.
// Copyright © 2020 zhaoliang chen. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "ZLBaseEventModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface ZLCollectionViewBackgroundViewLayoutAttributes : UICollectionViewLayoutAttributes
//此属性只是header会单独设置其他均直接返回其frame属性
@property(nonatomic,assign,readonly)CGRect headerFrame;
@property(nonatomic,assign,readonly)CGRect footerFrame;
@property(nonatomic,copy)NSString* eventName;
@property(nonatomic,copy)id parameter;
- (void)callMethod:(ZLBaseEventModel*)eventModel;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,45 @@
//
// ZLCollectionViewBackViewLayoutAttributes.m
// ZLCollectionView
//
// Created by zhaoliang chen on 2020/4/17.
// Copyright © 2020 zhaoliang chen. All rights reserved.
//
#import "ZLCollectionViewBackgroundViewLayoutAttributes.h"
@implementation ZLCollectionViewBackgroundViewLayoutAttributes
@synthesize headerFrame = _headerFrame;
@synthesize footerFrame = _footerFrame;
+ (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind withIndexPath:(NSIndexPath *)indexPath orginalFrmae:(CGRect)orginalFrame{
ZLCollectionViewBackgroundViewLayoutAttributes *layoutAttributes = [super layoutAttributesForDecorationViewOfKind:decorationViewKind withIndexPath:indexPath];
[layoutAttributes setValue:[NSValue valueWithCGRect:orginalFrame] forKey:@"orginalFrame"];
layoutAttributes.frame = orginalFrame;
return layoutAttributes;
}
-(CGRect)orginalFrame {
if ([self.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
return _headerFrame;
} else if ([self.representedElementKind isEqualToString:UICollectionElementKindSectionFooter]) {
return _footerFrame;
} else {
return self.frame;
}
}
- (void)callMethod:(ZLBaseEventModel*)eventModel {
NSAssert([eventModel isKindOfClass:[ZLBaseEventModel class]], @"callMethod必须传入ZLBaseEventModel类型参数");
if (eventModel == nil) {
return;
}
if (eventModel.eventName != nil) {
self.eventName = eventModel.eventName;
}
if (eventModel.parameter) {
self.parameter = eventModel.parameter;
}
}
@end

View File

@@ -0,0 +1,136 @@
//
// ZLCollectionViewBaseFlowLayout.h
// ZLCollectionView
//
// Created by zhaoliang chen on 2019/1/25.
// Copyright © 2019 zhaoliang chen. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "ZLBaseEventModel.h"
/**
版本1.4.9
*/
NS_ASSUME_NONNULL_BEGIN
typedef enum {
LabelHorizontalLayout = 1, //标签横向
LabelVerticalLayout = 2, //标签纵向
LabelLayout = LabelHorizontalLayout, //标签页布局。 一堆label标签的集合
ClosedLayout = 3,
ColumnLayout = ClosedLayout, //列布局 指定列数按列数来等分一整行itemSize的width可以任意写在布局中会自动帮你计算。可用于瀑布流普通UITableViewCell
PercentLayout = 4, //百分比布局 需实现percentOfRow的代理根据设定值来计算每个itemSize的宽度
FillLayout = 5, //填充式布局 将一堆大小不一的view见缝插针的填充到一个平面内规则为先判断从左到右是否有间隙填充再从上到下判断。
AbsoluteLayout = 6, //绝对定位布局 需实现rectOfItem的代理指定每个item的frame
} ZLLayoutType;
typedef enum {
minHeight = 1, // 按最小高度
Sequence = 2, // 按顺序
} ZLColumnSortType;
@class ZLCollectionViewBaseFlowLayout;
@protocol ZLCollectionViewBaseFlowLayoutDelegate <NSObject, UICollectionViewDelegateFlowLayout>
@optional
//指定是什么布局如没有指定则为FillLayout(填充式布局)
- (ZLLayoutType)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout typeOfLayout:(NSInteger)section;
/******** 设置每个section的背景色 ***********/
//设置每个section的背景色
- (UIColor*)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout backColorForSection:(NSInteger)section;
//设置每个section的背景图
- (UIImage*)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout backImageForSection:(NSInteger)section;
//自定义每个section的背景view需要继承UICollectionReusableView(如要调用方法传递参数需要继承ZLCollectionBaseDecorationView),返回类名
- (NSString*)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout registerBackView:(NSInteger)section;
//向每个section自定义背景view传递自定义方法 eventName:方法名(注意带参数的方法名必须末尾加:,parameter:参数
- (ZLBaseEventModel*)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout backgroundViewMethodForSection:(NSInteger)section;
//背景是否延伸覆盖到headerView默认为NO
- (BOOL)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout attachToTop:(NSInteger)section;
//背景是否延伸覆盖到footerView默认为NO
- (BOOL)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout attachToBottom:(NSInteger)section;
/******** 提取出UICollectionViewLayoutAttributes的一些属性 ***********/
//设置每个item的zIndex不指定默认为0
- (NSInteger)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout zIndexOfItem:(NSIndexPath*)indexPath;
//设置每个item的CATransform3D不指定默认为CATransform3DIdentity
- (CATransform3D)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout transformOfItem:(NSIndexPath*)indexPath;
//设置每个item的alpha不指定默认为1
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout alphaOfItem:(NSIndexPath*)indexPath;
/******** ClosedLayout列布局需要的代理 ***********/
//在ClosedLayout列布局中指定一行有几列不指定默认为1列
- (NSInteger)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout*)collectionViewLayout columnCountOfSection:(NSInteger)section;
//在ClosedLayout列布局中指定哪列哪行可以是单行布局不指定以上个方法为准
- (BOOL)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout*)collectionViewLayout singleColumnCountOfIndexPath:(NSIndexPath*)indexPath;
/******** PercentLayout百分比布局需要的代理 ***********/
//在PercentLayout百分比布局中指定每个item占该行的几分之几如3.0/4注意为大于0小于等于1的数字。不指定默认为1
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout*)collectionViewLayout percentOfRow:(NSIndexPath*)indexPath;
/******** AbsoluteLayout绝对定位布局需要的代理 ***********/
//在AbsoluteLayout绝对定位布局中指定每个item的frame不指定默认为CGRectZero
- (CGRect)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout*)collectionViewLayout rectOfItem:(NSIndexPath*)indexPath;
/******** 拖动cell的相关代理 ***************************/
//- (BOOL)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout*)collectionViewLayout shouldMoveCell:(NSIndexPath*)indexPath;
- (void)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout*)collectionViewLayout didMoveCell:(NSIndexPath*)atIndexPath toIndexPath:(NSIndexPath*)toIndexPath;
@end
/***
此类是基类,不要调用。
纵向布局请调用 #import "ZLCollectionViewVerticalLayout.h"
横向布局请调用 #import "ZLCollectionViewHorzontalLayout.h"
***/
@interface ZLCollectionViewBaseFlowLayout : UICollectionViewFlowLayout
@property (nonatomic,weak) id<ZLCollectionViewBaseFlowLayoutDelegate> delegate;
@property (nonatomic,assign) BOOL isFloor; // 宽度是否向下取整默认YES用于填充布局未来加入百分比布局
@property (nonatomic,assign) BOOL canDrag; //是否允许拖动cell默认是NO
@property (nonatomic,assign) BOOL header_suspension; //头部是否悬浮默认是NO
@property (nonatomic,assign) ZLLayoutType layoutType; //指定layout的类型也可以在代理里设置
@property (nonatomic,assign) NSInteger columnCount; //指定列数
@property (nonatomic,assign) ZLColumnSortType columnSortType; // 瀑布流列排序的方式
@property (nonatomic,assign) CGFloat fixTop; //header偏移量
@property (nonatomic,assign) CGFloat xBeyond; //x轴允许超出的偏移量仅填充布局默认3px
//每个section的每一列的高度
@property (nonatomic, strong) NSMutableArray *collectionHeightsArray;
//存放每一个cell的属性
@property (nonatomic, strong) NSMutableArray *attributesArray;
//存放header属性, 外部不要干预
@property (nonatomic, strong, readonly) NSMutableArray *headerAttributesArray;
//是否需要重新计算所有布局
//内部控制,一般情况外部无需干预(内部会在外部调用reloadData,insertSections,insertItems,deleteItems...等方法调用时将此属性自动置为YES)
@property (nonatomic, assign, readonly) BOOL isNeedReCalculateAllLayout;
//提供一个方法来设置isNeedReCalculateAllLayout (之所以提供是因为特殊情况下外部可能需要强制重新计算布局)
//比如需要强制刷新布局时可以先调用此函数设置为YES, 一般情况外部无需干预
- (void)forceSetIsNeedReCalculateAllLayout:(BOOL)isNeedReCalculateAllLayout;
// 注册所有的背景view(传入类名)
- (void)registerDecorationView:(NSArray<NSString*>*)classNames;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,527 @@
//
// ZLCollectionViewBaseFlowLayout.m
// ZLCollectionView
//
// Created by zhaoliang chen on 2019/1/25.
// Copyright © 2019 zhaoliang chen. All rights reserved.
//
#import "ZLCollectionViewBaseFlowLayout.h"
#import "ZLCollectionViewLayoutAttributes.h"
#import "ZLCellFakeView.h"
typedef NS_ENUM(NSUInteger, LewScrollDirction) {
LewScrollDirctionStay,
LewScrollDirctionToTop,
LewScrollDirctionToEnd,
};
@interface ZLCollectionViewBaseFlowLayout ()
<UIGestureRecognizerDelegate>
//
@property (nonatomic, strong) ZLCellFakeView *cellFakeView;
@property (nonatomic, strong) UILongPressGestureRecognizer *longPress;
@property (nonatomic, strong) UIPanGestureRecognizer *panGesture;
@property (nonatomic, assign) CGPoint fakeCellCenter;
@property (nonatomic, assign) CGPoint panTranslation;
@property (nonatomic) LewScrollDirction continuousScrollDirection;
@property (nonatomic, strong) CADisplayLink *displayLink;
@end
@implementation ZLCollectionViewBaseFlowLayout {
BOOL _isNeedReCalculateAllLayout;
}
- (instancetype)init {
if (self == [super init]) {
self.isFloor = YES;
self.canDrag = NO;
self.header_suspension = NO;
self.layoutType = FillLayout;
self.columnCount = 1;
self.columnSortType = minHeight;
self.fixTop = 0;
self.xBeyond = 3;
_isNeedReCalculateAllLayout = YES;
_headerAttributesArray = @[].mutableCopy;
[self addObserver:self forKeyPath:@"collectionView" options:NSKeyValueObservingOptionNew context:nil];
}
return self;
}
#pragma mark -
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
return self.header_suspension;
}
//+ (Class)layoutAttributesClass {
// return [ZLCollectionViewLayoutAttributes class];
//}
- (void)invalidateLayoutWithContext:(UICollectionViewLayoutInvalidationContext *)context {
//relaodData
//
//,,
_isNeedReCalculateAllLayout = context.invalidateEverything || context.invalidateDataSourceCounts;
[super invalidateLayoutWithContext:context];
}
// view()
- (void)registerDecorationView:(NSArray<NSString*>*)classNames {
for (NSString* className in classNames) {
if (className.length > 0) {
[self registerClass:NSClassFromString(className) forDecorationViewOfKind:className];
}
}
}
- (void)dealloc {
[self removeObserver:self forKeyPath:@"collectionView"];
}
#pragma mark - cellview
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
if (!self.attributesArray || self.collectionView.numberOfSections == 0) {
return [super layoutAttributesForElementsInRect:rect];
} else {
if (self.header_suspension) {
//headerAttributesArray
for (UICollectionViewLayoutAttributes *attriture in self.headerAttributesArray) {
if (![attriture.representedElementKind isEqualToString:UICollectionElementKindSectionHeader])
continue;
NSInteger section = attriture.indexPath.section;
CGRect frame = attriture.frame;
BOOL isNeedChangeFrame = NO;
if (section == 0) {
if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
CGFloat offsetY = self.collectionView.contentOffset.y + self.fixTop;
if (offsetY > 0 && offsetY < [self.collectionHeightsArray[0] floatValue]) {
frame.origin.y = offsetY;
attriture.zIndex = 1000+section;
attriture.frame = frame;
isNeedChangeFrame = YES;
}
} else {
CGFloat offsetX = self.collectionView.contentOffset.y + self.fixTop;
if (offsetX > 0 && offsetX < [self.collectionHeightsArray[0] floatValue]) {
frame.origin.x = offsetX;
attriture.zIndex = 1000+section;
attriture.frame = frame;
isNeedChangeFrame = YES;
}
}
} else {
if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
CGFloat offsetY = self.collectionView.contentOffset.y + self.fixTop;
if (offsetY > [self.collectionHeightsArray[section-1] floatValue] &&
offsetY < [self.collectionHeightsArray[section] floatValue]) {
frame.origin.y = offsetY;
attriture.zIndex = 1000+section;
attriture.frame = frame;
isNeedChangeFrame = YES;
}
} else {
CGFloat offsetX = self.collectionView.contentOffset.y + self.fixTop;
if (offsetX > [self.collectionHeightsArray[section-1] floatValue] &&
offsetX < [self.collectionHeightsArray[section] floatValue]) {
frame.origin.x = offsetX;
attriture.zIndex = 1000+section;
attriture.frame = frame;
isNeedChangeFrame = YES;
}
}
}
if (!isNeedChangeFrame) {
/*
headerAttframe
header,headerAtt
header
*/
if ([attriture isKindOfClass:[ZLCollectionViewLayoutAttributes class]]) {
attriture.frame = ((ZLCollectionViewLayoutAttributes*)attriture).orginalFrame;
}
}
}
}
return self.attributesArray;
}
}
// 1.4.8layoutAttributesForItemAtIndexPath
//- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
// UICollectionViewLayoutAttributes *layoutAttributes = (UICollectionViewLayoutAttributes*)self.attributesArray[indexPath.item];
// if(!layoutAttributes) {
// layoutAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];
// }
// return layoutAttributes;
//}
/**
*/
#pragma mark
- (void)setCanDrag:(BOOL)canDrag {
_canDrag = canDrag;
if (canDrag) {
if (self.longPress == nil && self.panGesture == nil) {
[self setUpGestureRecognizers];
}
} else {
[self.collectionView removeGestureRecognizer:self.longPress];
self.longPress.delegate = nil;
self.longPress = nil;
[self.collectionView removeGestureRecognizer:self.panGesture];
self.panGesture.delegate = nil;
self.panGesture = nil;
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if ([keyPath isEqualToString:@"collectionView"]) {
if (self.canDrag) {
[self setUpGestureRecognizers];
}
}else{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)setUpGestureRecognizers{
if (self.collectionView == nil) {
return;
}
self.longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(handleLongPress:)];
self.panGesture = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(handlePanGesture:)];
self.longPress.delegate = self;
self.panGesture.delegate = self;
self.panGesture.maximumNumberOfTouches = 1;
NSArray *gestures = [self.collectionView gestureRecognizers];
__weak typeof(ZLCollectionViewBaseFlowLayout*) weakSelf = self;
[gestures enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[UILongPressGestureRecognizer class]]) {
[(UILongPressGestureRecognizer *)obj requireGestureRecognizerToFail:weakSelf.longPress];
}
}];
[self.collectionView addGestureRecognizer:self.longPress];
[self.collectionView addGestureRecognizer:self.panGesture];
}
#pragma mark - gesture
- (void)handleLongPress:(UILongPressGestureRecognizer *)longPress {
CGPoint location = [longPress locationInView:self.collectionView];
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:location];
// __weak typeof(ZLCollectionViewBaseFlowLayout*) weakSelf = self;
// if ([weakSelf.delegate respondsToSelector:@selector(collectionView:layout:shouldMoveCell:)]) {
// if ([weakSelf.delegate collectionView:weakSelf.collectionView layout:weakSelf shouldMoveCell:indexPath] == NO) {
// return;
// }
// }
if (_cellFakeView != nil) {
indexPath = self.cellFakeView.indexPath;
}
if (indexPath == nil) {
return;
}
switch (longPress.state) {
case UIGestureRecognizerStateBegan:{
// will begin drag item
self.collectionView.scrollsToTop = NO;
UICollectionViewCell *currentCell = [self.collectionView cellForItemAtIndexPath:indexPath];
self.cellFakeView = [[ZLCellFakeView alloc]initWithCell:currentCell];
self.cellFakeView.indexPath = indexPath;
self.cellFakeView.originalCenter = currentCell.center;
self.cellFakeView.cellFrame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
[self.collectionView addSubview:self.cellFakeView];
self.fakeCellCenter = self.cellFakeView.center;
[self invalidateLayout];
[self.cellFakeView pushFowardView];
}
break;
case UIGestureRecognizerStateCancelled:
case UIGestureRecognizerStateEnded:
[self cancelDrag:indexPath];
default:
break;
}
}
// pan gesture
- (void)handlePanGesture:(UIPanGestureRecognizer *)pan {
_panTranslation = [pan translationInView:self.collectionView];
if (_cellFakeView != nil) {
switch (pan.state) {
case UIGestureRecognizerStateChanged:{
CGPoint center = _cellFakeView.center;
center.x = self.fakeCellCenter.x + self.panTranslation.x;
center.y = self.fakeCellCenter.y + self.panTranslation.y;
self.cellFakeView.center = center;
[self beginScrollIfNeeded];
[self moveItemIfNeeded];
}
break;
case UIGestureRecognizerStateCancelled:
case UIGestureRecognizerStateEnded:
[self invalidateDisplayLink];
default:
break;
}
}
}
// gesture recognize delegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
// allow move item
CGPoint location = [gestureRecognizer locationInView:self.collectionView];
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:location];
if (!indexPath) {
return NO;
}
if ([gestureRecognizer isEqual:self.longPress]){
return (self.collectionView.panGestureRecognizer.state == UIGestureRecognizerStatePossible || self.collectionView.panGestureRecognizer.state == UIGestureRecognizerStateFailed);
} else if ([gestureRecognizer isEqual:self.panGesture]){
return (self.longPress.state != UIGestureRecognizerStatePossible && self.longPress.state != UIGestureRecognizerStateFailed);
}
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if ([self.panGesture isEqual:gestureRecognizer]) {
return [self.longPress isEqual:otherGestureRecognizer];
} else if ([self.collectionView.panGestureRecognizer isEqual:gestureRecognizer]) {
return (self.longPress.state != UIGestureRecognizerStatePossible && self.longPress.state != UIGestureRecognizerStateFailed);
}
return YES;
}
- (void)cancelDrag:(NSIndexPath *)toIndexPath {
if (self.cellFakeView == nil) {
return;
}
self.collectionView.scrollsToTop = YES;
self.fakeCellCenter = CGPointZero;
[self invalidateDisplayLink];
__weak typeof(ZLCollectionViewBaseFlowLayout*) weakSelf = self;
[self.cellFakeView pushBackView:^{
[weakSelf.cellFakeView removeFromSuperview];
weakSelf.cellFakeView = nil;
[weakSelf invalidateLayout];
}];
}
- (void)beginScrollIfNeeded{
if (self.cellFakeView == nil) {
return;
}
CGFloat offset = self.scrollDirection == UICollectionViewScrollDirectionVertical ? self.collectionView.contentOffset.y : self.collectionView.contentOffset.x;
CGFloat trigerInsetTop = self.scrollDirection == UICollectionViewScrollDirectionVertical ? self.collectionView.contentInset.top: self.collectionView.contentInset.left;
CGFloat trigerInsetEnd = self.scrollDirection == UICollectionViewScrollDirectionVertical ? self.collectionView.contentInset.bottom : self.collectionView.contentInset.right;
CGFloat paddingTop = 0;
CGFloat paddingEnd = 0;
CGFloat length = self.scrollDirection == UICollectionViewScrollDirectionVertical ? self.collectionView.frame.size.height : self.collectionView.frame.size.width;
CGFloat fakeCellTopEdge = self.scrollDirection == UICollectionViewScrollDirectionVertical ? CGRectGetMinY(self.cellFakeView.frame) : CGRectGetMinX(self.cellFakeView.frame);
CGFloat fakeCellEndEdge = self.scrollDirection == UICollectionViewScrollDirectionVertical ? CGRectGetMaxY(self.cellFakeView.frame) : CGRectGetMaxX(self.cellFakeView.frame);
if(fakeCellTopEdge <= offset + paddingTop + trigerInsetTop){
self.continuousScrollDirection = LewScrollDirctionToTop;
[self setUpDisplayLink];
}else if(fakeCellEndEdge >= offset + length - paddingEnd - trigerInsetEnd) {
self.continuousScrollDirection = LewScrollDirctionToEnd;
[self setUpDisplayLink];
}else {
[self invalidateDisplayLink];
}
}
// move item
- (void)moveItemIfNeeded {
NSIndexPath *atIndexPath = nil;
NSIndexPath *toIndexPath = nil;
__weak typeof(ZLCollectionViewBaseFlowLayout*) weakSelf = self;
if (self.cellFakeView) {
atIndexPath = _cellFakeView.indexPath;
toIndexPath = [self.collectionView indexPathForItemAtPoint:_cellFakeView.center];
}
if (atIndexPath.section != toIndexPath.section) {
return;
}
// if ([weakSelf.delegate respondsToSelector:@selector(collectionView:layout:shouldMoveCell:)]) {
// if ([weakSelf.delegate collectionView:weakSelf.collectionView layout:weakSelf shouldMoveCell:toIndexPath] == NO) {
// return;
// }
// }
if (atIndexPath == nil || toIndexPath == nil) {
return;
}
if ([atIndexPath isEqual:toIndexPath]) {
return;
}
UICollectionViewLayoutAttributes *attribute = nil;//[self layoutAttributesForItemAtIndexPath:toIndexPath];
for (ZLCollectionViewLayoutAttributes* attr in weakSelf.attributesArray) {
if (attr.indexPath.section == toIndexPath.section && attr.indexPath.item == toIndexPath.item &&
attr.representedElementKind != UICollectionElementKindSectionHeader &&
attr.representedElementKind != UICollectionElementKindSectionFooter) {
attribute = attr;
break;
}
}
//NSLog(@"拖动从%@到%@",atIndexPath,toIndexPath);
if (attribute != nil) {
[self.collectionView performBatchUpdates:^{
weakSelf.cellFakeView.indexPath = toIndexPath;
weakSelf.cellFakeView.cellFrame = attribute.frame;
[weakSelf.cellFakeView changeBoundsIfNeeded:attribute.bounds];
[weakSelf.collectionView moveItemAtIndexPath:atIndexPath toIndexPath:toIndexPath];
if ([weakSelf.delegate respondsToSelector:@selector(collectionView:layout:didMoveCell:toIndexPath:)]) {
[weakSelf.delegate collectionView:weakSelf.collectionView layout:weakSelf didMoveCell:atIndexPath toIndexPath:toIndexPath];
}
} completion:nil];
}
}
- (void)setUpDisplayLink{
if (_displayLink) {
return;
}
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(continuousScroll)];
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
- (void)invalidateDisplayLink{
_continuousScrollDirection = LewScrollDirctionStay;
[_displayLink invalidate];
_displayLink = nil;
}
- (void)continuousScroll{
if (_cellFakeView == nil) {
return;
}
CGFloat percentage = [self calcTrigerPercentage];
CGFloat scrollRate = [self scrollValueWithSpeed:10 andPercentage:percentage];
CGFloat offset = 0;
CGFloat insetTop = 0;
CGFloat insetEnd = 0;
CGFloat length = self.scrollDirection == UICollectionViewScrollDirectionVertical ? self.collectionView.frame.size.height : self.collectionView.frame.size.width;
CGFloat contentLength = self.scrollDirection == UICollectionViewScrollDirectionVertical ? self.collectionView.contentSize.height : self.collectionView.contentSize.width;
if (contentLength + insetTop + insetEnd <= length) {
return;
}
if (offset + scrollRate <= -insetTop) {
scrollRate = -insetTop - offset;
} else if (offset + scrollRate >= contentLength + insetEnd - length) {
scrollRate = contentLength + insetEnd - length - offset;
}
__weak typeof(ZLCollectionViewBaseFlowLayout*) weakSelf = self;
[self.collectionView performBatchUpdates:^{
if (weakSelf.scrollDirection == UICollectionViewScrollDirectionVertical) {
CGPoint point = weakSelf.fakeCellCenter;
point.y += scrollRate;
weakSelf.fakeCellCenter = point;
CGPoint center = weakSelf.cellFakeView.center;
center.y = weakSelf.fakeCellCenter.y + weakSelf.panTranslation.y;
weakSelf.cellFakeView.center = center;
CGPoint contentOffset = weakSelf.collectionView.contentOffset;
contentOffset.y += scrollRate;
weakSelf.collectionView.contentOffset = contentOffset;
} else {
CGPoint point = weakSelf.fakeCellCenter;
point.x += scrollRate;
weakSelf.fakeCellCenter = point;
//_fakeCellCenter.x += scrollRate;
CGPoint center = weakSelf.cellFakeView.center;
center.x = weakSelf.fakeCellCenter.x + weakSelf.panTranslation.x;
weakSelf.cellFakeView.center = center;
CGPoint contentOffset = weakSelf.collectionView.contentOffset;
contentOffset.x += scrollRate;
weakSelf.collectionView.contentOffset = contentOffset;
}
} completion:nil];
[self moveItemIfNeeded];
}
- (CGFloat)calcTrigerPercentage{
if (_cellFakeView == nil) {
return 0;
}
CGFloat offset = 0;
CGFloat offsetEnd = 0 + self.scrollDirection == UICollectionViewScrollDirectionVertical ? self.collectionView.frame.size.height : self.collectionView.frame.size.width;
CGFloat insetTop = 0;
CGFloat trigerInsetTop = 0;
CGFloat trigerInsetEnd = 0;
CGFloat paddingTop = 0;
CGFloat paddingEnd = 0;
CGFloat percentage = 0.0;
if (self.continuousScrollDirection == LewScrollDirctionToTop) {
if (self.cellFakeView) {
percentage = 1.0 - (((self.scrollDirection == UICollectionViewScrollDirectionVertical ? self.cellFakeView.frame.origin.y : self.cellFakeView.frame.origin.x) - (offset + paddingTop)) / trigerInsetTop);
}
} else if (self.continuousScrollDirection == LewScrollDirctionToEnd){
if (self.cellFakeView) {
percentage = 1.0 - (((insetTop + offsetEnd - paddingEnd) - ((self.scrollDirection == UICollectionViewScrollDirectionVertical ? self.cellFakeView.frame.origin.y : self.cellFakeView.frame.origin.x) + (self.scrollDirection == UICollectionViewScrollDirectionVertical ? self.cellFakeView.frame.size.height : self.cellFakeView.frame.size.width) + insetTop)) / trigerInsetEnd);
}
}
percentage = fmin(1.0f, percentage);
percentage = fmax(0.0f, percentage);
return percentage;
}
#pragma mark - getter
- (CGFloat)scrollValueWithSpeed:(CGFloat)speed andPercentage:(CGFloat)percentage{
CGFloat value = 0.0f;
switch (_continuousScrollDirection) {
case LewScrollDirctionStay: {
return 0.0f;
break;
}
case LewScrollDirctionToTop: {
value = -speed;
break;
}
case LewScrollDirctionToEnd: {
value = speed;
break;
}
default: {
return 0.0f;
}
}
CGFloat proofedPercentage = fmax(fmin(1.0f, percentage), 0.0f);
return value * proofedPercentage;
}
- (void)forceSetIsNeedReCalculateAllLayout:(BOOL)isNeedReCalculateAllLayout
{
_isNeedReCalculateAllLayout = isNeedReCalculateAllLayout;
}
@end

View File

@@ -0,0 +1,17 @@
//
// ZLCollectionViewHorzontalLayout.h
// ZLCollectionView
//
// Created by zhaoliang chen on 2019/1/25.
// Copyright © 2019 zhaoliang chen. All rights reserved.
//
#import "ZLCollectionViewBaseFlowLayout.h"
NS_ASSUME_NONNULL_BEGIN
@interface ZLCollectionViewHorzontalLayout : ZLCollectionViewBaseFlowLayout
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,362 @@
//
// ZLCollectionViewHorzontalLayout.m
// ZLCollectionView
//
// Created by zhaoliang chen on 2019/1/25.
// Copyright © 2019 zhaoliang chen. All rights reserved.
//
#import "ZLCollectionViewHorzontalLayout.h"
#import "ZLCollectionReusableView.h"
#import "ZLCollectionViewLayoutAttributes.h"
#import "ZLCollectionViewBackgroundViewLayoutAttributes.h"
@interface ZLCollectionViewHorzontalLayout()
@end
@implementation ZLCollectionViewHorzontalLayout
#pragma mark -
- (instancetype)init {
self = [super init];
if (self) {
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
}
return self;
}
- (void)prepareLayout {
[super prepareLayout];
//怀...
if (!self.isNeedReCalculateAllLayout) {
return;
}
CGFloat totalHeight = self.collectionView.frame.size.height;
CGFloat x = 0;
CGFloat y = 0;
CGFloat headerW = 0;
CGFloat footerW = 0;
UIEdgeInsets edgeInsets = UIEdgeInsetsZero;
CGFloat minimumLineSpacing = 0;
CGFloat minimumInteritemSpacing = 0;
NSUInteger sectionCount = [self.collectionView numberOfSections];
self.attributesArray = [NSMutableArray new];
self.collectionHeightsArray = [NSMutableArray arrayWithCapacity:sectionCount];
for (int index= 0; index<sectionCount; index++) {
NSUInteger itemCount = [self.collectionView numberOfItemsInSection:index];
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForHeaderInSection:)]) {
headerW = [self.delegate collectionView:self.collectionView layout:self referenceSizeForHeaderInSection:index].width;
} else {
headerW = self.headerReferenceSize.width;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForFooterInSection:)]) {
footerW = [self.delegate collectionView:self.collectionView layout:self referenceSizeForFooterInSection:index].width;
} else {
footerW = self.footerReferenceSize.width;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) {
edgeInsets = [self.delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:index];
} else {
edgeInsets = self.sectionInset;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:minimumLineSpacingForSectionAtIndex:)]) {
minimumLineSpacing = [self.delegate collectionView:self.collectionView layout:self minimumLineSpacingForSectionAtIndex:index];
} else {
minimumLineSpacing = self.minimumLineSpacing;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:minimumInteritemSpacingForSectionAtIndex:)]) {
minimumInteritemSpacing = [self.delegate collectionView:self.collectionView layout:self minimumInteritemSpacingForSectionAtIndex:index];
} else {
minimumInteritemSpacing = self.minimumInteritemSpacing;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:registerBackView:)]) {
NSString* className = [self.delegate collectionView:self.collectionView layout:self registerBackView:index];
if (className != nil && className.length > 0) {
NSAssert([[NSClassFromString(className) alloc]init]!=nil, @"代理collectionView:layout:registerBackView:里面必须返回有效的类名!");
[self registerClass:NSClassFromString(className) forDecorationViewOfKind:className];
} else {
[self registerClass:[ZLCollectionReusableView class] forDecorationViewOfKind:@"ZLCollectionReusableView"];
}
}
else {
[self registerClass:[ZLCollectionReusableView class] forDecorationViewOfKind:@"ZLCollectionReusableView"];
}
x = [self maxHeightWithSection:index];
y = edgeInsets.top;
//
if (headerW > 0) {
NSIndexPath *headerIndexPath = [NSIndexPath indexPathForItem:0 inSection:index];
ZLCollectionViewLayoutAttributes* headerAttr = [ZLCollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader withIndexPath:headerIndexPath];
headerAttr.frame = CGRectMake(x, 0, headerW, self.collectionView.frame.size.height);
[headerAttr setValue:[NSValue valueWithCGRect:headerAttr.frame] forKey:@"orginalFrame"];
[self.attributesArray addObject:headerAttr];
[self.headerAttributesArray addObject:headerAttr];
}
x += headerW ;
CGFloat itemStartX = x;
CGFloat lastX = x;
if (itemCount > 0) {
x += edgeInsets.left;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:typeOfLayout:)]) {
self.layoutType = [self.delegate collectionView:self.collectionView layout:self typeOfLayout:index];
}
NSAssert((self.layoutType==LabelVerticalLayout||self.layoutType==ColumnLayout||self.layoutType==AbsoluteLayout), @"横向布局暂时只支持LabelVerticalLayout,ColumnLayout,AbsoluteLayout!");
//NSInteger columnCount = 1;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:columnCountOfSection:)]) {
self.columnCount = [self.delegate collectionView:self.collectionView layout:self columnCountOfSection:index];
}
//
CGFloat *columnWidths = (CGFloat *) malloc(self.columnCount * sizeof(CGFloat));
CGFloat itemHeight = 0.0;
if (self.layoutType == ClosedLayout) {
for (int i=0; i<self.columnCount; i++) {
columnWidths[i] = x;
}
itemHeight = (totalHeight - edgeInsets.top - edgeInsets.bottom - minimumInteritemSpacing * (self.columnCount - 1)) / self.columnCount;
}
NSInteger lastColumnIndex = 0;
NSMutableArray* arrayOfAbsolute = [NSMutableArray new]; //
for (int i=0; i<itemCount; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:index];
CGSize itemSize = CGSizeZero;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:sizeForItemAtIndexPath:)]) {
itemSize = [self.delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
} else {
itemSize = self.itemSize;
}
ZLCollectionViewLayoutAttributes *attributes = [ZLCollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
NSInteger preRow = self.attributesArray.count - 1;
switch (self.layoutType) {
#pragma mark
case LabelVerticalLayout: {
//cell
if(preRow >= 0){
if(i > 0) {
ZLCollectionViewLayoutAttributes *preAttr = self.attributesArray[preRow];
y = preAttr.frame.origin.y + preAttr.frame.size.height + minimumInteritemSpacing;
if (y + itemSize.height > totalHeight - edgeInsets.bottom) {
y = edgeInsets.top;
x += itemSize.width + minimumLineSpacing;
}
}
}
attributes.frame = CGRectMake(x, y, itemSize.width, itemSize.height);
}
break;
case LabelHorizontalLayout: {
}
break;
#pragma mark |
case ClosedLayout: {
CGFloat max = CGFLOAT_MAX;
NSInteger column = 0;
if (self.columnSortType == Sequence) {
column = lastColumnIndex;
} else {
for (int i = 0; i < self.columnCount; i++) {
if (columnWidths[i] < max) {
max = columnWidths[i];
column = i;
}
}
}
CGFloat itemX = columnWidths[column];
CGFloat itemY = edgeInsets.top + (itemHeight+minimumInteritemSpacing)*column;
attributes.frame = CGRectMake(itemX, itemY, itemSize.width, itemHeight);
columnWidths[column] += (itemSize.width + minimumLineSpacing);
lastColumnIndex++;
if (lastColumnIndex >= self.columnCount) {
lastColumnIndex = 0;
}
}
break;
case AbsoluteLayout: {
CGRect itemFrame = CGRectZero;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:rectOfItem:)]) {
itemFrame = [self.delegate collectionView:self.collectionView layout:self rectOfItem:indexPath];
}
CGFloat absolute_x = x+itemFrame.origin.x;
CGFloat absolute_y = edgeInsets.top+itemFrame.origin.y;
CGFloat absolute_h = itemFrame.size.height;
if ((absolute_y+absolute_h>self.collectionView.frame.size.height-edgeInsets.bottom)&&(absolute_y<self.collectionView.frame.size.height-edgeInsets.top)) {
absolute_h -= (absolute_y+absolute_h-(self.collectionView.frame.size.height-edgeInsets.bottom));
}
CGFloat absolute_w = itemFrame.size.width;
attributes.frame = CGRectMake(absolute_x, absolute_y, absolute_w, absolute_h);
[arrayOfAbsolute addObject:attributes];
}
break;
default: {
}
break;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:transformOfItem:)]) {
attributes.transform3D = [self.delegate collectionView:self.collectionView layout:self transformOfItem:indexPath];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:zIndexOfItem:)]) {
attributes.zIndex = [self.delegate collectionView:self.collectionView layout:self zIndexOfItem:indexPath];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:alphaOfItem:)]) {
attributes.alpha = [self.delegate collectionView:self.collectionView layout:self alphaOfItem:indexPath];
}
attributes.indexPath = indexPath;
if (self.layoutType != PercentLayout) {
//if (![self.attributesArray containsObject:attributes]) {
[self.attributesArray addObject:attributes];
//}
}
if (self.layoutType == ClosedLayout) {
CGFloat max = 0;
for (int i = 0; i < self.columnCount; i++) {
if (columnWidths[i] > max) {
max = columnWidths[i];
}
}
lastX = max;
} else if (self.layoutType == AbsoluteLayout) {
if (i==itemCount-1) {
for (ZLCollectionViewLayoutAttributes* attr in arrayOfAbsolute) {
if (lastX < attr.frame.origin.x+attr.frame.size.width) {
lastX = attr.frame.origin.x+attr.frame.size.width;
}
}
}
} else {
lastX = attributes.frame.origin.x + attributes.frame.size.width;
}
}
free(columnWidths);
}
if (self.layoutType == ClosedLayout) {
if (itemCount > 0) {
lastX -= minimumLineSpacing;
}
}
if (itemCount > 0) {
lastX += edgeInsets.right;
}
//
if (footerW > 0) {
NSIndexPath *footerIndexPath = [NSIndexPath indexPathForItem:0 inSection:index];
ZLCollectionViewLayoutAttributes *footerAttr = [ZLCollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter withIndexPath:footerIndexPath];
footerAttr.frame = CGRectMake(lastX, 0, footerW, self.collectionView.frame.size.height);
[self.attributesArray addObject:footerAttr];
lastX += footerW;
}
#pragma mark
CGFloat backWidth = lastX-itemStartX+([self isAttachToTop:index]?headerW:0)-([self isAttachToBottom:index]?0:footerW);
if (backWidth < 0) {
backWidth = 0;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:registerBackView:)]) {
NSString* className = [self.delegate collectionView:self.collectionView layout:self registerBackView:index];
if (className != nil && className.length > 0) {
ZLCollectionViewBackgroundViewLayoutAttributes *attr = [ZLCollectionViewBackgroundViewLayoutAttributes layoutAttributesForDecorationViewOfKind:className withIndexPath:[NSIndexPath indexPathForRow:0 inSection:index]];
attr.frame = CGRectMake([self isAttachToTop:index]?itemStartX-headerW:itemStartX, 0, backWidth, self.collectionView.frame.size.height);
attr.zIndex = -1000;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:backgroundViewMethodForSection:)]) {
if ([self.delegate collectionView:self.collectionView layout:self backgroundViewMethodForSection:index] != nil) {
[attr callMethod:[self.delegate collectionView:self.collectionView layout:self backgroundViewMethodForSection:index]];
}
}
[self.attributesArray addObject:attr];
} else {
ZLCollectionViewLayoutAttributes *attr = [ZLCollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:@"ZLCollectionReusableView" withIndexPath:[NSIndexPath indexPathForRow:0 inSection:index]];
attr.frame = CGRectMake([self isAttachToTop:index]?itemStartX-headerW:itemStartX, 0, backWidth, self.collectionView.frame.size.height);
attr.color = self.collectionView.backgroundColor;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:backColorForSection:)]) {
attr.color = [self.delegate collectionView:self.collectionView layout:self backColorForSection:index];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:backImageForSection:)]) {
attr.image = [self.delegate collectionView:self.collectionView layout:self backImageForSection:index];
}
attr.zIndex = -1000;
[self.attributesArray addObject:attr];
}
} else {
ZLCollectionViewLayoutAttributes *attr = [ZLCollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:@"ZLCollectionReusableView" withIndexPath:[NSIndexPath indexPathForRow:0 inSection:index]];
attr.frame = CGRectMake([self isAttachToTop:index]?itemStartX-headerW:itemStartX, 0, backWidth, self.collectionView.frame.size.height);
attr.color = self.collectionView.backgroundColor;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:backColorForSection:)]) {
attr.color = [self.delegate collectionView:self.collectionView layout:self backColorForSection:index];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:backImageForSection:)]) {
attr.image = [self.delegate collectionView:self.collectionView layout:self backImageForSection:index];
}
attr.zIndex = -1000;
[self.attributesArray addObject:attr];
}
self.collectionHeightsArray[index] = [NSNumber numberWithFloat:lastX];
}
[self forceSetIsNeedReCalculateAllLayout:NO];
// for (int i=0; i<self.attributesArray.count; i++) {
// ZLCollectionViewLayoutAttributes* attr = self.attributesArray[i];
// NSLog(@"第%d个-----%@",i,NSStringFromCGRect(attr.frame));
// }
}
#pragma mark - CollectionView
- (CGSize)collectionViewContentSize
{
if (self.collectionHeightsArray.count <= 0) {
return CGSizeMake(self.collectionView.frame.size.width, self.collectionView.frame.size.height);
}
CGFloat footerW = 0.0f;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForFooterInSection:)]) {
footerW = [self.delegate collectionView:self.collectionView layout:self referenceSizeForFooterInSection:self.collectionHeightsArray.count-1].width;
} else {
footerW = self.footerReferenceSize.width;
}
UIEdgeInsets edgeInsets = UIEdgeInsetsZero;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) {
edgeInsets = [self.delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:self.collectionHeightsArray.count-1];
} else {
edgeInsets = self.sectionInset;
}
return CGSizeMake([self.collectionHeightsArray[self.collectionHeightsArray.count-1] floatValue], self.collectionView.frame.size.height);
}
/**
X
@param section
@return Y
*/
- (CGFloat)maxHeightWithSection:(NSInteger)section {
if (section>0) {
return [self.collectionHeightsArray[section-1] floatValue];
} else {
return 0;
}
}
- (BOOL)isAttachToTop:(NSInteger)section {
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:attachToTop:)]) {
return [self.delegate collectionView:self.collectionView layout:self attachToTop:section];
}
return NO;
}
- (BOOL)isAttachToBottom:(NSInteger)section {
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:attachToBottom:)]) {
return [self.delegate collectionView:self.collectionView layout:self attachToBottom:section];
}
return NO;
}
@end

View File

@@ -0,0 +1,21 @@
//
// ZLCollectionViewLayoutAttributes.h
// ZLCollectionView
//
// Created by zhaoliang chen on 2018/7/9.
// Copyright © 2018年 zhaoliang chen. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ZLCollectionViewLayoutAttributes : UICollectionViewLayoutAttributes
@property(nonatomic,copy)UIColor* color;
@property(nonatomic,copy)UIImage* image;
//此属性只是header会单独设置其他均直接返回其frame属性
@property(nonatomic,assign,readonly)CGRect orginalFrame;
@end

View File

@@ -0,0 +1,30 @@
//
// ZLCollectionViewLayoutAttributes.m
// ZLCollectionView
//
// Created by zhaoliang chen on 2018/7/9.
// Copyright © 2018 zhaoliang chen. All rights reserved.
//
#import "ZLCollectionViewLayoutAttributes.h"
#import "ZLCollectionReusableView.h"
@implementation ZLCollectionViewLayoutAttributes
@synthesize orginalFrame = _orginalFrame;
+ (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind withIndexPath:(NSIndexPath *)indexPath orginalFrmae:(CGRect)orginalFrame{
ZLCollectionViewLayoutAttributes *layoutAttributes = [super layoutAttributesForDecorationViewOfKind:decorationViewKind withIndexPath:indexPath];
[layoutAttributes setValue:[NSValue valueWithCGRect:orginalFrame] forKey:@"orginalFrame"];
layoutAttributes.frame = orginalFrame;
return layoutAttributes;
}
-(CGRect)orginalFrame {
if ([self.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
return _orginalFrame;
} else {
return self.frame;
}
}
@end

View File

@@ -0,0 +1,17 @@
//
// ZLCollectionViewVerticalLayout.h
// ZLCollectionView
//
// Created by zhaoliang chen on 2019/1/25.
// Copyright © 2019 zhaoliang chen. All rights reserved.
//
#import "ZLCollectionViewBaseFlowLayout.h"
NS_ASSUME_NONNULL_BEGIN
@interface ZLCollectionViewVerticalLayout : ZLCollectionViewBaseFlowLayout
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,750 @@
//
// ZLCollectionViewVerticalLayout.m
// ZLCollectionView
//
// Created by zhaoliang chen on 2019/1/25.
// Copyright © 2019 zhaoliang chen. All rights reserved.
//
#import "ZLCollectionViewVerticalLayout.h"
#import "ZLCollectionReusableView.h"
#import "ZLCollectionViewLayoutAttributes.h"
#import "ZLCollectionViewBackgroundViewLayoutAttributes.h"
@interface ZLCollectionViewVerticalLayout ()
@end
@implementation ZLCollectionViewVerticalLayout
#pragma mark -
- (instancetype)init {
self = [super init];
if (self) {
self.scrollDirection = UICollectionViewScrollDirectionVertical;
}
return self;
}
- (void)prepareLayout {
[super prepareLayout];
//怀...
if (!self.isNeedReCalculateAllLayout) {
return;
}
CGFloat totalWidth = self.collectionView.frame.size.width;
CGFloat x = 0;
CGFloat y = 0;
CGFloat headerH = 0;
CGFloat footerH = 0;
UIEdgeInsets edgeInsets = UIEdgeInsetsZero;
CGFloat minimumLineSpacing = 0;
CGFloat minimumInteritemSpacing = 0;
NSUInteger sectionCount = [self.collectionView numberOfSections];
self.attributesArray = [NSMutableArray new];
[self.headerAttributesArray removeAllObjects];
self.collectionHeightsArray = [NSMutableArray arrayWithCapacity:sectionCount];
for (int index= 0; index<sectionCount; index++) {
NSUInteger itemCount = [self.collectionView numberOfItemsInSection:index];
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForHeaderInSection:)]) {
headerH = [self.delegate collectionView:self.collectionView layout:self referenceSizeForHeaderInSection:index].height;
} else {
headerH = self.headerReferenceSize.height;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForFooterInSection:)]) {
footerH = [self.delegate collectionView:self.collectionView layout:self referenceSizeForFooterInSection:index].height;
} else {
footerH = self.footerReferenceSize.height;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) {
edgeInsets = [self.delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:index];
} else {
edgeInsets = self.sectionInset;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:minimumLineSpacingForSectionAtIndex:)]) {
minimumLineSpacing = [self.delegate collectionView:self.collectionView layout:self minimumLineSpacingForSectionAtIndex:index];
} else {
minimumLineSpacing = self.minimumLineSpacing;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:minimumInteritemSpacingForSectionAtIndex:)]) {
minimumInteritemSpacing = [self.delegate collectionView:self.collectionView layout:self minimumInteritemSpacingForSectionAtIndex:index];
} else {
minimumInteritemSpacing = self.minimumInteritemSpacing;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:registerBackView:)]) {
NSString* className = [self.delegate collectionView:self.collectionView layout:self registerBackView:index];
if (className != nil && className.length > 0) {
NSAssert([[NSClassFromString(className) alloc]init]!=nil, @"代理collectionView:layout:registerBackView:里面必须返回有效的类名!");
[self registerClass:NSClassFromString(className) forDecorationViewOfKind:className];
} else {
[self registerClass:[ZLCollectionReusableView class] forDecorationViewOfKind:@"ZLCollectionReusableView"];
}
} else {
[self registerClass:[ZLCollectionReusableView class] forDecorationViewOfKind:@"ZLCollectionReusableView"];
}
x = edgeInsets.left;
y = [self maxHeightWithSection:index];
//
if (headerH > 0) {
NSIndexPath *headerIndexPath = [NSIndexPath indexPathForItem:0 inSection:index];
ZLCollectionViewLayoutAttributes* headerAttr = [ZLCollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader withIndexPath:headerIndexPath];
headerAttr.frame = CGRectMake(0, y, self.collectionView.frame.size.width, headerH);
[headerAttr setValue:[NSValue valueWithCGRect:headerAttr.frame] forKey:@"orginalFrame"];
[self.attributesArray addObject:headerAttr];
[self.headerAttributesArray addObject:headerAttr];
}
y += headerH ;
CGFloat itemStartY = y;
CGFloat lastY = y;
if (itemCount > 0) {
y += edgeInsets.top;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:typeOfLayout:)]) {
self.layoutType = [self.delegate collectionView:self.collectionView layout:self typeOfLayout:index];
}
//NSInteger columnCount = 1;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:columnCountOfSection:)]) {
self.columnCount = [self.delegate collectionView:self.collectionView layout:self columnCountOfSection:index];
}
//
CGFloat *columnHeight = (CGFloat *) malloc(self.columnCount * sizeof(CGFloat));
CGFloat itemWidth = 0.0;
if (self.layoutType == ClosedLayout) {
for (int i=0; i<self.columnCount; i++) {
columnHeight[i] = y;
}
itemWidth = (totalWidth - edgeInsets.left - edgeInsets.right - minimumInteritemSpacing * (self.columnCount - 1)) / self.columnCount;
}
CGFloat maxYOfPercent = -1;
CGFloat maxYOfFill = y;
NSMutableArray* arrayOfPercent = [NSMutableArray new]; //
NSMutableArray* arrayOfFill = [NSMutableArray new]; //
NSMutableArray* arrayOfAbsolute = [NSMutableArray new]; //
NSMutableArray *arrayXOfFill = [NSMutableArray new]; //
[arrayXOfFill addObject:self.isFloor?@(floor(edgeInsets.left)):@(edgeInsets.left)];
NSMutableArray *arrayYOfFill = [NSMutableArray new]; //
[arrayYOfFill addObject:self.isFloor?@(floor(maxYOfFill)):@(maxYOfFill)];
NSInteger lastColumnIndex = 0;
for (int i=0; i<itemCount; i++) {
BOOL singleColumnCount = NO;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:singleColumnCountOfIndexPath:)]) {
singleColumnCount = [self.delegate collectionView:self.collectionView
layout:self
singleColumnCountOfIndexPath:[NSIndexPath indexPathForItem:i inSection:index]];
}
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:index];
CGSize itemSize = CGSizeZero;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:sizeForItemAtIndexPath:)]) {
itemSize = [self.delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
} else {
itemSize = self.itemSize;
}
ZLCollectionViewLayoutAttributes *attributes = [ZLCollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
NSInteger preRow = self.attributesArray.count - 1;
switch (self.layoutType) {
#pragma mark
case LabelLayout: {
//cell
if(preRow >= 0){
if(i > 0) {
ZLCollectionViewLayoutAttributes *preAttr = self.attributesArray[preRow];
x = preAttr.frame.origin.x + preAttr.frame.size.width + minimumInteritemSpacing;
if (x + itemSize.width > totalWidth - edgeInsets.right) {
x = edgeInsets.left;
y += itemSize.height + minimumLineSpacing;
}
}
}
if (itemSize.width > (totalWidth-edgeInsets.left-edgeInsets.right)) {
itemSize.width = (totalWidth-edgeInsets.left-edgeInsets.right);
}
attributes.frame = CGRectMake(x, y, itemSize.width, itemSize.height);
}
break;
#pragma mark
case ClosedLayout: {
if (singleColumnCount) {
CGFloat max = 0;
for (int i = 0; i < self.columnCount; i++) {
if (columnHeight[i] > max) {
max = columnHeight[i];
}
}
CGFloat itemX = 0;
CGFloat itemY = max;
attributes.frame = CGRectMake(edgeInsets.left + itemX, itemY, totalWidth-edgeInsets.left-edgeInsets.right, itemSize.height);
for (int i = 0; i < self.columnCount; i++) {
columnHeight[i] = max + itemSize.height + minimumLineSpacing;
}
lastColumnIndex = 0;
} else {
CGFloat max = CGFLOAT_MAX;
NSInteger column = 0;
if (self.columnSortType == Sequence) {
column = lastColumnIndex;
} else {
for (int i = 0; i < self.columnCount; i++) {
if (columnHeight[i] < max) {
max = columnHeight[i];
column = i;
}
}
}
CGFloat itemX = edgeInsets.left + (itemWidth+minimumInteritemSpacing)*column;
CGFloat itemY = columnHeight[column];
attributes.frame = CGRectMake(itemX, itemY, itemWidth, itemSize.height);
columnHeight[column] += (itemSize.height + minimumLineSpacing);
lastColumnIndex++;
if (lastColumnIndex >= self.columnCount) {
lastColumnIndex = 0;
}
}
}
break;
#pragma mark
case PercentLayout: {
CGFloat percent = 0.0f;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:percentOfRow:)]) {
percent = [self.delegate collectionView:self.collectionView layout:self percentOfRow:indexPath];
} else {
percent = 1;
}
if (percent > 1 || percent <= 0) {
percent = 1;
}
if (arrayOfPercent.count > 0) {
CGFloat totalPercent = 0;
for (NSDictionary* dic in arrayOfPercent) {
totalPercent += [dic[@"percent"] floatValue];
}
if ((totalPercent+percent) >= 1.0) {
if ((totalPercent+percent) < 1.1) {
//1.1
//
attributes.indexPath = indexPath;
attributes.frame = CGRectMake(0, 0, (itemSize.width>self.collectionView.frame.size.width-edgeInsets.left-edgeInsets.right)?self.collectionView.frame.size.width-edgeInsets.left-edgeInsets.right:itemSize.width, itemSize.height);
//
[arrayOfPercent addObject:[NSMutableDictionary dictionaryWithDictionary:@{@"item":attributes,@"percent":[NSNumber numberWithFloat:percent],@"indexPath":indexPath}]];
if ((totalPercent+percent) > 1) {
NSMutableDictionary* lastDic = [NSMutableDictionary dictionaryWithDictionary:arrayOfPercent.lastObject];
CGFloat lastPercent = 1.0;
for (NSInteger i=0; i<arrayOfPercent.count-1; i++) {
NSMutableDictionary* dic = arrayOfPercent[i];
lastPercent -= [dic[@"percent"] floatValue];
}
lastDic[@"percent"] = [NSNumber numberWithFloat:lastPercent];
[arrayOfPercent replaceObjectAtIndex:arrayOfPercent.count-1 withObject:lastDic];
}
CGFloat realWidth = totalWidth - edgeInsets.left - edgeInsets.right - (arrayOfPercent.count-1)*minimumInteritemSpacing;
for (NSInteger i=0; i<arrayOfPercent.count; i++) {
NSDictionary* dic = arrayOfPercent[i];
ZLCollectionViewLayoutAttributes *newAttributes = dic[@"item"];
CGFloat itemX = 0.0f;
if (i==0) {
itemX = edgeInsets.left;
} else {
ZLCollectionViewLayoutAttributes *preAttr = arrayOfPercent[i-1][@"item"];
itemX = preAttr.frame.origin.x + preAttr.frame.size.width + minimumInteritemSpacing;
}
newAttributes.frame = CGRectMake(itemX, (maxYOfPercent==-1)?y:maxYOfPercent+minimumLineSpacing, realWidth*[dic[@"percent"] floatValue], newAttributes.frame.size.height);
newAttributes.indexPath = dic[@"indexPath"];
//if (![self.attributesArray containsObject:newAttributes]) {
[self.attributesArray addObject:newAttributes];
//}
}
for (NSInteger i=0; i<arrayOfPercent.count; i++) {
NSDictionary* dic = arrayOfPercent[i];
ZLCollectionViewLayoutAttributes *item = dic[@"item"];
if ((item.frame.origin.y + item.frame.size.height) > maxYOfPercent) {
maxYOfPercent = (item.frame.origin.y + item.frame.size.height);
}
}
[arrayOfPercent removeAllObjects];
}
else {
//
if (arrayOfPercent.count > 0) {
for (int i=0; i<arrayOfPercent.count; i++) {
NSDictionary* dic = arrayOfPercent[i];
ZLCollectionViewLayoutAttributes* attr = dic[@"item"];
if ((attr.frame.origin.y+attr.frame.size.height) > maxYOfPercent ) {
maxYOfPercent = attr.frame.origin.y+attr.frame.size.height;
}
}
}
attributes.indexPath = indexPath;
attributes.frame = CGRectMake(edgeInsets.left, maxYOfPercent, (itemSize.width>self.collectionView.frame.size.width-edgeInsets.left-edgeInsets.right)?self.collectionView.frame.size.width-edgeInsets.left-edgeInsets.right:itemSize.width, itemSize.height);
for (int i=0; i<arrayOfPercent.count; i++) {
NSDictionary* dic = arrayOfPercent[i];
ZLCollectionViewLayoutAttributes* attr = dic[@"item"];
attr.indexPath = dic[@"indexPath"];
[self.attributesArray addObject:attr];
}
[arrayOfPercent removeAllObjects];
//
[arrayOfPercent addObject:[NSMutableDictionary dictionaryWithDictionary:@{@"item":attributes,@"percent":[NSNumber numberWithFloat:percent],@"indexPath":indexPath}]];
//item1item
if (i==itemCount-1) {
CGFloat realWidth = totalWidth - edgeInsets.left - edgeInsets.right - (arrayOfPercent.count-1)*minimumInteritemSpacing;
for (NSInteger i=0; i<arrayOfPercent.count; i++) {
NSDictionary* dic = arrayOfPercent[i];
ZLCollectionViewLayoutAttributes *newAttributes = dic[@"item"];
CGFloat itemX = 0.0f;
if (i==0) {
itemX = edgeInsets.left;
} else {
ZLCollectionViewLayoutAttributes *preAttr = arrayOfPercent[i-1][@"item"];
itemX = preAttr.frame.origin.x + preAttr.frame.size.width + minimumInteritemSpacing;
}
newAttributes.frame = CGRectMake(itemX, (maxYOfPercent==-1)?y:maxYOfPercent+minimumLineSpacing, realWidth*[dic[@"percent"] floatValue], newAttributes.frame.size.height);
newAttributes.indexPath = dic[@"indexPath"];
[self.attributesArray addObject:newAttributes];
}
for (NSInteger i=0; i<arrayOfPercent.count; i++) {
NSDictionary* dic = arrayOfPercent[i];
ZLCollectionViewLayoutAttributes *item = dic[@"item"];
if ((item.frame.origin.y + item.frame.size.height) > maxYOfPercent) {
maxYOfPercent = (item.frame.origin.y + item.frame.size.height);
}
}
[arrayOfPercent removeAllObjects];
}
}
}
else {
//
attributes.indexPath = indexPath;
NSDictionary* lastDicForPercent = arrayOfPercent[arrayOfPercent.count-1];
ZLCollectionViewLayoutAttributes *lastAttributesForPercent = lastDicForPercent[@"item"];
attributes.frame = CGRectMake(lastAttributesForPercent.frame.origin.x+lastAttributesForPercent.frame.size.width+minimumInteritemSpacing, lastAttributesForPercent.frame.origin.y, itemSize.width, itemSize.height);
//
[arrayOfPercent addObject:[NSMutableDictionary dictionaryWithDictionary:@{@"item":attributes,@"percent":[NSNumber numberWithFloat:percent],@"indexPath":indexPath}]];
//
if (i==itemCount-1) {
NSInteger space = arrayOfPercent.count-1;
if (arrayOfPercent.count > 0) {
NSDictionary* dic = arrayOfPercent[0];
BOOL equal = YES;
for (NSDictionary* d in arrayOfPercent) {
if ([dic[@"percent"] floatValue] != [d[@"percent"] floatValue]) {
equal = NO;
break;
}
}
if (equal == YES) {
space = (1/([dic[@"percent"] floatValue]))-1;
}
}
CGFloat realWidth = totalWidth - edgeInsets.left - edgeInsets.right - space*minimumInteritemSpacing;
for (NSInteger i=0; i<arrayOfPercent.count; i++) {
NSDictionary* dic = arrayOfPercent[i];
ZLCollectionViewLayoutAttributes *newAttributes = dic[@"item"];
CGFloat itemX = 0.0f;
if (i==0) {
itemX = edgeInsets.left;
} else {
ZLCollectionViewLayoutAttributes *preAttr = arrayOfPercent[i-1][@"item"];
itemX = preAttr.frame.origin.x + preAttr.frame.size.width + minimumInteritemSpacing;
}
newAttributes.frame = CGRectMake(itemX, (maxYOfPercent==-1)?y:maxYOfPercent+minimumLineSpacing, realWidth*[dic[@"percent"] floatValue], newAttributes.frame.size.height);
newAttributes.indexPath = dic[@"indexPath"];
//if (![self.attributesArray containsObject:newAttributes]) {
[self.attributesArray addObject:newAttributes];
//}
}
for (NSInteger i=0; i<arrayOfPercent.count; i++) {
NSDictionary* dic = arrayOfPercent[i];
ZLCollectionViewLayoutAttributes *item = dic[@"item"];
if ((item.frame.origin.y + item.frame.size.height) > maxYOfPercent) {
maxYOfPercent = (item.frame.origin.y + item.frame.size.height);
}
}
[arrayOfPercent removeAllObjects];
} else {
}
}
}
else {
//
attributes.indexPath = indexPath;
attributes.frame = CGRectMake(edgeInsets.left, (maxYOfPercent==-1)?y:maxYOfPercent+minimumLineSpacing, (itemSize.width>self.collectionView.frame.size.width-edgeInsets.left-edgeInsets.right)?self.collectionView.frame.size.width-edgeInsets.left-edgeInsets.right:itemSize.width, itemSize.height);
//
[arrayOfPercent addObject:[NSMutableDictionary dictionaryWithDictionary:@{@"item":attributes,@"percent":[NSNumber numberWithFloat:percent],@"indexPath":indexPath}]];
//
if (i==itemCount-1) {
NSInteger space = arrayOfPercent.count-1;
if (arrayOfPercent.count > 0) {
NSDictionary* dic = arrayOfPercent[0];
BOOL equal = YES;
for (NSDictionary* d in arrayOfPercent) {
if ([dic[@"percent"] floatValue] != [d[@"percent"] floatValue]) {
equal = NO;
break;
}
}
if (equal == YES) {
space = (1/([dic[@"percent"] floatValue]))-1;
}
}
CGFloat realWidth = totalWidth - edgeInsets.left - edgeInsets.right - space*minimumInteritemSpacing;
for (NSInteger i=0; i<arrayOfPercent.count; i++) {
NSDictionary* dic = arrayOfPercent[i];
ZLCollectionViewLayoutAttributes *newAttributes = dic[@"item"];
CGFloat itemX = 0.0f;
if (i==0) {
itemX = edgeInsets.left;
} else {
ZLCollectionViewLayoutAttributes *preAttr = arrayOfPercent[i-1][@"item"];
itemX = preAttr.frame.origin.x + preAttr.frame.size.width + minimumInteritemSpacing;
}
newAttributes.frame = CGRectMake(itemX, (maxYOfPercent==-1)?y:maxYOfPercent+minimumLineSpacing, realWidth*[dic[@"percent"] floatValue], newAttributes.frame.size.height);
newAttributes.indexPath = dic[@"indexPath"];
[self.attributesArray addObject:newAttributes];
}
for (NSInteger i=0; i<arrayOfPercent.count; i++) {
NSDictionary* dic = arrayOfPercent[i];
ZLCollectionViewLayoutAttributes *item = dic[@"item"];
if ((item.frame.origin.y + item.frame.size.height) > maxYOfPercent) {
maxYOfPercent = (item.frame.origin.y + item.frame.size.height);
}
}
[arrayOfPercent removeAllObjects];
} else {
}
}
}
break;
#pragma mark
case FillLayout: {
BOOL qualified = YES;
if (arrayOfFill.count == 0) {
attributes.frame = CGRectMake(self.isFloor?floor(edgeInsets.left):edgeInsets.left, self.isFloor?floor(maxYOfFill):maxYOfFill, self.isFloor?floor(itemSize.width):itemSize.width, self.isFloor?floor(itemSize.height):itemSize.height);
[arrayOfFill addObject:attributes];
} else {
BOOL leftQualified = NO;
BOOL topQualified = NO;
for (NSNumber* yFill in arrayYOfFill) {
for (NSNumber* xFill in arrayXOfFill) {
qualified = YES;
CGFloat attrX = self.isFloor?(floor([xFill floatValue])==floor(edgeInsets.left)?floor([xFill floatValue]):(floor([xFill floatValue])+minimumInteritemSpacing)):([xFill floatValue]==edgeInsets.left?[xFill floatValue]:([xFill floatValue]+minimumInteritemSpacing));
CGFloat attrY = (fabs([yFill floatValue] - maxYOfFill) < 0.0001) ? [yFill floatValue] : [yFill floatValue] + minimumLineSpacing;
if (self.isFloor) {
attrY = floor([yFill floatValue])==floor(maxYOfFill)?floor([yFill floatValue]):floor([yFill floatValue])+floor(minimumLineSpacing);
}
attributes.frame = CGRectMake(attrX, attrY, self.isFloor?floor(itemSize.width):itemSize.width, self.isFloor?floor(itemSize.height):itemSize.height);
if (self.isFloor) {
if (floor(attributes.frame.origin.x)+floor(attributes.frame.size.width) > floor(totalWidth)-floor(edgeInsets.right)) {
qualified = NO;
break;
}
} else {
if (attributes.frame.origin.x+attributes.frame.size.width > totalWidth-edgeInsets.right+self.xBeyond) {
qualified = NO;
break;
}
}
for (ZLCollectionViewLayoutAttributes* attr in arrayOfFill) {
if (CGRectIntersectsRect(attributes.frame, attr.frame)) {
qualified = NO;
break;
}
}
if (qualified == NO) {
continue;
} else {
// cell
CGPoint leftPt = CGPointMake(attributes.frame.origin.x - floor(minimumInteritemSpacing), attributes.frame.origin.y);
CGRect leftRect = CGRectZero;
for (ZLCollectionViewLayoutAttributes* attr in arrayOfFill) {
if (CGRectContainsPoint(attr.frame, leftPt)) {
leftRect = attr.frame;
break;
}
}
if (CGRectEqualToRect(leftRect, CGRectZero)) {
leftQualified = YES;
} else {
if (attributes.frame.origin.x - (leftRect.origin.x + leftRect.size.width) >= floor(minimumInteritemSpacing)) {
leftQualified = YES;
} else if (floor(leftRect.origin.x) + floor(leftRect.size.width) <= leftPt.x) {
leftQualified = YES;
} else {
CGRect rc = attributes.frame;
rc.origin.x = leftRect.origin.x + leftRect.size.width + floor(minimumInteritemSpacing);
attributes.frame = rc;
for (ZLCollectionViewLayoutAttributes* attr in arrayOfFill) {
if (CGRectIntersectsRect(attributes.frame, attr.frame)) {
qualified = NO;
break;
}
}
}
}
// cell
CGPoint topPt = CGPointMake(attributes.frame.origin.x, attributes.frame.origin.y - floor(minimumLineSpacing));
CGRect topRect = CGRectZero;
for (ZLCollectionViewLayoutAttributes* attr in arrayOfFill) {
if (CGRectContainsPoint(attr.frame, topPt)) {
topRect = attr.frame;
break;
}
}
if (CGRectEqualToRect(topRect, CGRectZero)) {
topQualified = YES;
} else {
if (attributes.frame.origin.y - (topRect.origin.y + topRect.size.height) >= floor(minimumLineSpacing)) {
topQualified = YES;
} else if (floor(topRect.origin.y) + floor(topRect.size.height) <= topPt.y) {
topQualified = YES;
} else {
CGRect rc = attributes.frame;
rc.origin.y = topRect.origin.y + topRect.size.height + floor(minimumLineSpacing);
attributes.frame = rc;
for (ZLCollectionViewLayoutAttributes* attr in arrayOfFill) {
if (CGRectIntersectsRect(attributes.frame, attr.frame)) {
qualified = NO;
break;
}
}
}
}
if (leftQualified == YES && topQualified == YES) {
qualified = YES;
break;
}
}
}
if (qualified == YES) {
break;
}
}
if (qualified == YES) {
//NSLog(@"第%d个,合格的矩形区域=%@",i,NSStringFromCGRect(attributes.frame));
[arrayOfFill addObject:attributes];
}
}
if (qualified == YES) {
if (![arrayXOfFill containsObject:self.isFloor?@(floor(attributes.frame.origin.x)):@(attributes.frame.origin.x)]) {
[arrayXOfFill addObject:self.isFloor?@(floor(attributes.frame.origin.x)):@(attributes.frame.origin.x)];
}
if (![arrayXOfFill containsObject:self.isFloor?@(floor(attributes.frame.origin.x+attributes.frame.size.width)):@(attributes.frame.origin.x+attributes.frame.size.width)]) {
[arrayXOfFill addObject:self.isFloor?@(floor(attributes.frame.origin.x+attributes.frame.size.width)):@(attributes.frame.origin.x+attributes.frame.size.width)];
}
if (![arrayYOfFill containsObject:self.isFloor?@(floor(attributes.frame.origin.y)):@(attributes.frame.origin.y)]) {
[arrayYOfFill addObject:self.isFloor?@(floor(attributes.frame.origin.y)):@(attributes.frame.origin.y)];
}
if (![arrayYOfFill containsObject:self.isFloor?@(floor(attributes.frame.origin.y+attributes.frame.size.height)):@(attributes.frame.origin.y+attributes.frame.size.height)]) {
[arrayYOfFill addObject:self.isFloor?@(floor(attributes.frame.origin.y+attributes.frame.size.height)):@(attributes.frame.origin.y+attributes.frame.size.height)];
}
[arrayXOfFill sortUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
return [obj1 floatValue] > [obj2 floatValue];
}];
[arrayYOfFill sortUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
return [obj1 floatValue] > [obj2 floatValue];
}];
}
}
break;
#pragma mark
case AbsoluteLayout: {
CGRect itemFrame = CGRectZero;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:rectOfItem:)]) {
itemFrame = [self.delegate collectionView:self.collectionView layout:self rectOfItem:indexPath];
}
CGFloat absolute_x = edgeInsets.left+itemFrame.origin.x;
CGFloat absolute_y = y+itemFrame.origin.y;
CGFloat absolute_w = itemFrame.size.width;
if ((absolute_x+absolute_w>self.collectionView.frame.size.width-edgeInsets.right)&&(absolute_x<self.collectionView.frame.size.width-edgeInsets.right)) {
absolute_w -= (absolute_x+absolute_w-(self.collectionView.frame.size.width-edgeInsets.right));
}
CGFloat absolute_h = itemFrame.size.height;
attributes.frame = CGRectMake(absolute_x, absolute_y, absolute_w, absolute_h);
[arrayOfAbsolute addObject:attributes];
}
break;
default: {
//NSLog(@"%@",NSStringFromCGRect(attributes.frame));
}
break;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:transformOfItem:)]) {
attributes.transform3D = [self.delegate collectionView:self.collectionView layout:self transformOfItem:indexPath];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:zIndexOfItem:)]) {
attributes.zIndex = [self.delegate collectionView:self.collectionView layout:self zIndexOfItem:indexPath];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:alphaOfItem:)]) {
attributes.alpha = [self.delegate collectionView:self.collectionView layout:self alphaOfItem:indexPath];
}
attributes.indexPath = indexPath;
if (self.layoutType != PercentLayout) {
//if (![self.attributesArray containsObject:attributes]) {
[self.attributesArray addObject:attributes];
//}
}
if (self.layoutType == ClosedLayout) {
CGFloat max = 0;
for (int i = 0; i < self.columnCount; i++) {
if (columnHeight[i] > max) {
max = columnHeight[i];
}
}
lastY = max;
} else if (self.layoutType == PercentLayout) {
lastY = maxYOfPercent;
} else if (self.layoutType == FillLayout) {
if (i==itemCount-1) {
for (ZLCollectionViewLayoutAttributes* attr in arrayOfFill) {
if (maxYOfFill < attr.frame.origin.y+attr.frame.size.height) {
maxYOfFill = attr.frame.origin.y+attr.frame.size.height;
}
}
}
lastY = maxYOfFill;
} else if (self.layoutType == AbsoluteLayout) {
if (i==itemCount-1) {
for (ZLCollectionViewLayoutAttributes* attr in arrayOfAbsolute) {
if (lastY < attr.frame.origin.y+attr.frame.size.height) {
lastY = attr.frame.origin.y+attr.frame.size.height;
}
}
}
} else {
lastY = attributes.frame.origin.y + attributes.frame.size.height;
}
}
free(columnHeight);
}
if (self.layoutType == ClosedLayout) {
if (itemCount > 0) {
lastY -= minimumLineSpacing;
}
}
if (itemCount > 0) {
lastY += edgeInsets.bottom;
}
//
if (footerH > 0) {
NSIndexPath *footerIndexPath = [NSIndexPath indexPathForItem:0 inSection:index];
ZLCollectionViewLayoutAttributes *footerAttr = [ZLCollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter withIndexPath:footerIndexPath];
footerAttr.frame = CGRectMake(0, lastY, self.collectionView.frame.size.width, footerH);
[self.attributesArray addObject:footerAttr];
lastY += footerH;
}
#pragma mark
CGFloat backHeight = lastY-itemStartY+([self isAttachToTop:index]?headerH:0)-([self isAttachToBottom:index]?0:footerH);
if (backHeight < 0) {
backHeight = 0;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:registerBackView:)]) {
NSString* className = [self.delegate collectionView:self.collectionView layout:self registerBackView:index];
if (className != nil && className.length > 0) {
ZLCollectionViewBackgroundViewLayoutAttributes *attr = [ZLCollectionViewBackgroundViewLayoutAttributes layoutAttributesForDecorationViewOfKind:className withIndexPath:[NSIndexPath indexPathForRow:0 inSection:index]];
attr.frame = CGRectMake(0, [self isAttachToTop:index]?itemStartY-headerH:itemStartY, self.collectionView.frame.size.width, backHeight);
attr.zIndex = -1000;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:backgroundViewMethodForSection:)]) {
if ([self.delegate collectionView:self.collectionView layout:self backgroundViewMethodForSection:index] != nil) {
[attr callMethod:[self.delegate collectionView:self.collectionView layout:self backgroundViewMethodForSection:index]];
}
}
[self.attributesArray addObject:attr];
} else {
ZLCollectionViewLayoutAttributes *attr = [ZLCollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:@"ZLCollectionReusableView" withIndexPath:[NSIndexPath indexPathForRow:0 inSection:index]];
attr.frame = CGRectMake(0, [self isAttachToTop:index]?itemStartY-headerH:itemStartY, self.collectionView.frame.size.width, backHeight);
attr.color = self.collectionView.backgroundColor;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:backColorForSection:)]) {
attr.color = [self.delegate collectionView:self.collectionView layout:self backColorForSection:index];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:backImageForSection:)]) {
attr.image = [self.delegate collectionView:self.collectionView layout:self backImageForSection:index];
}
attr.zIndex = -1000;
[self.attributesArray addObject:attr];
}
} else {
ZLCollectionViewLayoutAttributes *attr = [ZLCollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:@"ZLCollectionReusableView" withIndexPath:[NSIndexPath indexPathForRow:0 inSection:index]];
attr.frame = CGRectMake(0, [self isAttachToTop:index]?itemStartY-headerH:itemStartY, self.collectionView.frame.size.width, backHeight);
attr.color = self.collectionView.backgroundColor;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:backColorForSection:)]) {
attr.color = [self.delegate collectionView:self.collectionView layout:self backColorForSection:index];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:backImageForSection:)]) {
attr.image = [self.delegate collectionView:self.collectionView layout:self backImageForSection:index];
}
attr.zIndex = -1000;
[self.attributesArray addObject:attr];
}
self.collectionHeightsArray[index] = [NSNumber numberWithFloat:lastY];
}
// for (ZLCollectionViewLayoutAttributes* attr in self.attributesArray) {
// NSLog(@"类型=%@,尺寸=%@",attr.representedElementKind, NSStringFromCGRect(attr.frame));
// }
[self forceSetIsNeedReCalculateAllLayout:NO];
}
#pragma mark - CollectionView
- (CGSize)collectionViewContentSize
{
if (self.collectionHeightsArray.count <= 0) {
return CGSizeMake(self.collectionView.frame.size.width, self.collectionView.frame.size.height);
}
CGFloat footerH = 0.0f;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForFooterInSection:)]) {
footerH = [self.delegate collectionView:self.collectionView layout:self referenceSizeForFooterInSection:self.collectionHeightsArray.count-1].height;
} else {
footerH = self.footerReferenceSize.height;
}
UIEdgeInsets edgeInsets = UIEdgeInsetsZero;
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) {
edgeInsets = [self.delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:self.collectionHeightsArray.count-1];
} else {
edgeInsets = self.sectionInset;
}
return CGSizeMake(self.collectionView.frame.size.width, [self.collectionHeightsArray[self.collectionHeightsArray.count-1] floatValue]);// + edgeInsets.bottom + footerH);
}
/**
Y
@param section
@return Y
*/
- (CGFloat)maxHeightWithSection:(NSInteger)section {
if (section>0) {
return [self.collectionHeightsArray[section-1] floatValue];
} else {
return 0;
}
}
- (BOOL)isAttachToTop:(NSInteger)section {
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:attachToTop:)]) {
return [self.delegate collectionView:self.collectionView layout:self attachToTop:section];
}
return NO;
}
- (BOOL)isAttachToBottom:(NSInteger)section {
if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:attachToBottom:)]) {
return [self.delegate collectionView:self.collectionView layout:self attachToBottom:section];
}
return NO;
}
@end