// // 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 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= 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 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; i0) { 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