iOS 瀑布流

下面這些是外部封裝的接口:

@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;

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容