Files
featherVoice/QXLive/Third/ZLCollectionViewFlowLayout/ZLCollectionViewVerticalLayout.m
2025-08-08 10:49:36 +08:00

751 lines
49 KiB
Objective-C
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// 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