增加换肤功能
This commit is contained in:
25
QXLive/Third/ZLCollectionViewFlowLayout/ZLBaseEventModel.h
Normal file
25
QXLive/Third/ZLCollectionViewFlowLayout/ZLBaseEventModel.h
Normal 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
|
||||
35
QXLive/Third/ZLCollectionViewFlowLayout/ZLBaseEventModel.m
Normal file
35
QXLive/Third/ZLCollectionViewFlowLayout/ZLBaseEventModel.m
Normal 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
|
||||
25
QXLive/Third/ZLCollectionViewFlowLayout/ZLCellFakeView.h
Normal file
25
QXLive/Third/ZLCollectionViewFlowLayout/ZLCellFakeView.h
Normal 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
|
||||
100
QXLive/Third/ZLCollectionViewFlowLayout/ZLCellFakeView.m
Normal file
100
QXLive/Third/ZLCollectionViewFlowLayout/ZLCellFakeView.m
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
136
QXLive/Third/ZLCollectionViewFlowLayout/ZLCollectionViewBaseFlowLayout.h
Executable file
136
QXLive/Third/ZLCollectionViewFlowLayout/ZLCollectionViewBaseFlowLayout.h
Executable 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
|
||||
527
QXLive/Third/ZLCollectionViewFlowLayout/ZLCollectionViewBaseFlowLayout.m
Executable file
527
QXLive/Third/ZLCollectionViewFlowLayout/ZLCollectionViewBaseFlowLayout.m
Executable 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 - 所有cell和view的布局属性
|
||||
- (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) {
|
||||
/*
|
||||
这里需要注意,在悬浮的情况下改变了headerAtt的frame
|
||||
在滑出header又滑回来时,headerAtt已经被修改过,需要改回原始值
|
||||
否则header无法正确归位
|
||||
*/
|
||||
if ([attriture isKindOfClass:[ZLCollectionViewLayoutAttributes class]]) {
|
||||
attriture.frame = ((ZLCollectionViewLayoutAttributes*)attriture).orginalFrame;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return self.attributesArray;
|
||||
}
|
||||
}
|
||||
|
||||
// 1.4.8暂时去掉layoutAttributesForItemAtIndexPath方法
|
||||
//- (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
|
||||
@@ -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
|
||||
362
QXLive/Third/ZLCollectionViewFlowLayout/ZLCollectionViewHorzontalLayout.m
Executable file
362
QXLive/Third/ZLCollectionViewFlowLayout/ZLCollectionViewHorzontalLayout.m
Executable 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
|
||||
21
QXLive/Third/ZLCollectionViewFlowLayout/ZLCollectionViewLayoutAttributes.h
Executable file
21
QXLive/Third/ZLCollectionViewFlowLayout/ZLCollectionViewLayoutAttributes.h
Executable 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
|
||||
30
QXLive/Third/ZLCollectionViewFlowLayout/ZLCollectionViewLayoutAttributes.m
Executable file
30
QXLive/Third/ZLCollectionViewFlowLayout/ZLCollectionViewLayoutAttributes.m
Executable 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
|
||||
@@ -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
|
||||
750
QXLive/Third/ZLCollectionViewFlowLayout/ZLCollectionViewVerticalLayout.m
Executable file
750
QXLive/Third/ZLCollectionViewFlowLayout/ZLCollectionViewVerticalLayout.m
Executable 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}]];
|
||||
//如果该行item总比例还是小于1,但是item已经是最后一个
|
||||
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
|
||||
Reference in New Issue
Block a user