下面這些是外部封裝的接口:
@interface LRBWaterFallLayout : UICollectionViewLayout
@property (nonatomic) NSMutableArray * modelAry;
/**
*? 最小行間距
*/
@property (nonatomic) CGFloat minimumLineSpacing;
/**
*? 最小item之間的距離
*/
@property (nonatomic) CGFloat minimumInteritemSpacing;
/**
*? 內(nèi)邊距
*/
@property (nonatomic) UIEdgeInsets sectionInset;
/**
*? 總列數(shù)
*/
@property (nonatomic) NSUInteger columns;
@end
下面這些是那些常規(guī)的方法
//屏幕bounds#define SCREEN_BOUNSE ([UIScreen mainScreen].bounds)
//屏幕寬度#define SCREEN_WIDTH? (SCREEN_BOUNSE.size.width)
@interface LRBWaterFallLayout ()
/** *? 記錄每一列的高度 */
@property (nonatomic) NSMutableArray *heightArray;
/** *? 記錄每一個(gè)item的屬性 */
@property (nonatomic) NSMutableArray *attrArray;
@end
@implementation LRBWaterFallLayout
//重寫方法
//準(zhǔn)備布局,布局之前準(zhǔn)備工作全部做完
- (void)prepareLayout{? ??
//1.創(chuàng)建高度數(shù)組? ??
if (self.heightArray == nil) {? ? ? ??
//沒有數(shù)組創(chuàng)建數(shù)組? ? ? ??
self.heightArray = [NSMutableArray array];? ?
?}else{? ? ? ??
//有數(shù)組將原來數(shù)組里面的內(nèi)容全部清空? ? ? ??
[self.heightArray removeAllObjects];? ??
}? ? ? ??
if (self.attrArray == nil) {? ? ? ??
self.attrArray = [NSMutableArray array];? ?
?}else{? ? ? ?
?[self.attrArray removeAllObjects];? ?
?}? ? ? ?
?//2.初始化高度數(shù)組? ??
for (int i = 0; i < self.columns; i++) {? ? ? ??
[self.heightArray addObject:@(self.sectionInset.top)];? ?
?}? ? ? ??
//3.計(jì)算item的寬度? ?
?CGFloat totalWidth = SCREEN_WIDTH;? ??
CGFloat validWidth = totalWidth - self.sectionInset.left - self.sectionInset.right - (self.columns - 1) * self.minimumInteritemSpacing;? ?
?CGFloat itemWidth = validWidth / self.columns;? ? ? ??
//4.開始布局每個(gè)item? ??
//取出item的總個(gè)數(shù)? ?
?NSUInteger totalCount = [self.collectionView numberOfItemsInSection:0];? ?
?for (int i = 0; i < totalCount; i++) {? ? ? ?
?//取出最短列的下標(biāo)? ? ? ??
NSUInteger minIndex = [self minIndexOfColumn];? ? ? ??
//求item的x坐標(biāo)? ? ? ??
CGFloat itemX = self.sectionInset.left + minIndex * (itemWidth + self.minimumInteritemSpacing);? ? ? ?
?//求item的y坐標(biāo)? ? ? ?
?CGFloat itemY = [self.heightArray[minIndex] floatValue];? ? ? ?
?//得到item的高度? ? ? ?
?LRBFirstOneItemOfPicsModel * oneItems = self.modelAry[i];? ? ? ? LRBFirstInfoModel * firstInfo = oneItems.data.info;? ? ? ?
?CGFloat rate = [firstInfo.img_h floatValue] / [firstInfo.img_w floatValue];? ? ? ? CGFloat itemHeight = itemWidth * rate + 20;? ? ? ??
//創(chuàng)建item的屬性對象? ? ? ??
NSIndexPath *itemIndexPath = [NSIndexPath indexPathForItem:i inSection:0];? ? ? ? UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:itemIndexPath];? ? ? ?
?//將item的frame存放到item的屬性對象中? ? ? ?
?attr.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight);? ? ? ??
//將item屬性對象,存放到屬性數(shù)組中? ? ? ??
[self.attrArray addObject:attr];? ? ? ? ? ? ? ?
?//更新高度數(shù)組中的高度? ? ??
?CGFloat height = [self.heightArray[minIndex] floatValue] + itemHeight + self.minimumLineSpacing ;? ? ? ?
?[self.heightArray replaceObjectAtIndex:minIndex withObject:@(height)];? ?
?}
}
//重寫方法
//所有的item的屬性對象,只要frame和rect有交集,這些屬性對象我都要,將其存放到數(shù)組中返回
- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect
{
//存放所有和rect有交集的item屬性對象
NSMutableArray *mulArray = [NSMutableArray array];
for (UICollectionViewLayoutAttributes *attr in self.attrArray) {
//判斷每一個(gè)attr的frame和rect是否有交集,如果有交集的話存放到數(shù)組中
if (CGRectIntersectsRect(attr.frame, rect)) {
[mulArray addObject:attr];
}
}
return mulArray;
}
//重寫方法
//返回集合視圖的內(nèi)容尺寸
- (CGSize)collectionViewContentSize
{
//得到所有列中最高列的下標(biāo)
NSUInteger maxIndex = [self maxIndexOfColumn];
//獲取內(nèi)容尺寸的最大值
CGFloat height = [self.heightArray[maxIndex] floatValue] + self.sectionInset.bottom;
//每一個(gè)布局對象里面都有一個(gè)指針指向當(dāng)前集合視圖,可以通過這個(gè)指針拿到當(dāng)前集合視圖
CGFloat width = SCREEN_WIDTH;
//返回集合視圖的內(nèi)容尺寸
return CGSizeMake(width, height);
}
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}
//每列中最短列的下標(biāo)
- (NSUInteger)minIndexOfColumn
{
NSUInteger index = 0;
for (int i = 1; i < self.heightArray.count; i++) {
if ([self.heightArray[index] floatValue] > [self.heightArray[i] floatValue]) {
index = i;
}
}
return index;
}
//每列中最長列的下標(biāo)
- (NSUInteger)maxIndexOfColumn
{
NSUInteger index = 0;
for (int i = 1; i < self.heightArray.count; i++) {
if ([self.heightArray[index] floatValue] < [self.heightArray[i] floatValue]) {
index = i;
}
}
return index;
}
@end
然而只有上面的這些的時(shí)候,在一開始就將item的個(gè)數(shù)確定,以及不需要復(fù)用的時(shí)候是可行的。在需要復(fù)用的時(shí)候,會(huì)出錯(cuò),錯(cuò)誤提示為:*** Assertion failure in -[UICollectionViewData layoutAttributesForItemAtIndexPath:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3512.30.14/UICollectionViewData.m:666
為了解決上述問題,實(shí)現(xiàn)方法[UICollectionViewData layoutAttributesForItemAtIndexPath:],對每個(gè)item的屬性進(jìn)行設(shè)置,即可解決,實(shí)現(xiàn)方法如下:
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes * attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
CGFloat totalWidth = SCREEN_WIDTH;
CGFloat validWidth = totalWidth - self.sectionInset.left - self.sectionInset.right - (self.columns - 1) * self.minimumInteritemSpacing;
CGFloat itemWidth = validWidth / self.columns;
NSUInteger minIndex = [self minIndexOfColumn];
//求item的x坐標(biāo)
CGFloat itemX = self.sectionInset.left + minIndex * (itemWidth + self.minimumInteritemSpacing);
//求item的y坐標(biāo)
CGFloat itemY = [self.heightArray[minIndex] floatValue];
LRBFirstOneItemOfPicsModel * oneItems = self.modelAry[indexPath.row];
LRBFirstInfoModel * firstInfo = oneItems.data.info;
CGFloat rate = [firstInfo.img_h floatValue] / [firstInfo.img_w floatValue];
CGFloat itemHeight = itemWidth * rate + 20;
attr.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight);
return attr;
}
在使用storyboard拉出來的collectionView的時(shí)候,進(jìn)行布局,可采用下述方法進(jìn)行調(diào)用以實(shí)現(xiàn)瀑布流:
weakSelf.collectionV.collectionViewLayout = [self waterFallLayout];
- (UICollectionViewLayout *)waterFallLayout{
LRBWaterFallLayout * layout = [[LRBWaterFallLayout alloc] init];
layout.minimumInteritemSpacing = 10;
layout.minimumLineSpacing = 10;
layout.columns = 2;
layout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
layout.modelAry = _dataSource;
return layout;
}