效果的實現,主要是對UICollectionViewLayout進行封裝,個人.h文件中:html
#import <UIKit/UIKit.h> @class CustomeViewLayout; @protocol CustomViewLayoutDelegate <NSObject> /** 計算item高度的代理方法,將item的高度與indexPath傳給外界 */ - (CGFloat)customFallLayout:(CustomeViewLayout *)customFallLayout itemHeightForWidth:(CGFloat)itemWidth atIndexPath:(NSIndexPath *)indexPath; @end //實現了瀑布流功能,可是不能添加頭部和底部視圖,如項目中有添加頭部或底部視圖的需求,請慎用!!! @interface CustomeViewLayout : UICollectionViewLayout /** 總列數,默認是2 */ @property (nonatomic, assign) NSInteger columnCount; /** 列間距,默認是0 */ @property (nonatomic, assign) float columnSpacing; /** 行間距,默認是0 */ @property (nonatomic, assign) float rowSpacing; /** section與CollectionView的間距,上、左、下、右,默認是(0, 0, 0, 0) */ @property (nonatomic, assign) UIEdgeInsets sectionInset; /** 同時設置列間距、行間距、sectionInset @param columnSpacing 列間距 @param rowSpacing 行間距 @param sectionInset 設置上、左、下、右的距離 */ - (void)setColumnSpacing:(float)columnSpacing rowSpacing:(float)rowSpacing sectionInset:(UIEdgeInsets)sectionInset; #pragma mark ====== 代理方法、block二選其一 ====== /** 一下代理屬性與block屬性二選其一,用來設置每個item的高度 會將item的高度與indexPath傳遞給外界 若是兩個都設置,block的優先級高,即代理無效 */ /** 代理方法,用來計算item的高度 */ @property (nonatomic, assign) id<CustomViewLayoutDelegate> delegate; /** 計算item高度的block,將item的高度與indexPath傳遞給外界 */ @property (nonatomic, strong) CGFloat(^itemHeightBlock)(CGFloat itemHeight, NSIndexPath *indexPath); #pragma mark ====== 構造方法 ====== + (instancetype)customFallLayoutWithColumnCount:(float)columnCount; - (instancetype)initWithColumCount:(float)columnCount; @end
上面的文件主要是給外界提供一個接口,能夠設置行數、行間距、列間距app
實現的文件中,主要是找到UICollectionView中,最短的列數的最大Y值,把後面須要添加的item添加到這一列的下面,主要代碼以下:atom
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { //根據indexPath獲取item的attributes UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; //獲取collectionView的寬度 CGFloat collectionViewWidth = self.collectionView.frame.size.width; //item的寬度 = (collectionView的寬度 - 內邊距與列間距) / 列數 CGFloat itemWidth = (collectionViewWidth - self.sectionInset.left - self.sectionInset.right - (self.columnCount - 1) * self.columnSpacing) / self.columnCount; CGFloat itemHeight = 0; //獲取item的高度,由外界計算獲得 if (self.itemHeightBlock) { itemHeight = self.itemHeightBlock(itemWidth, indexPath); } else { if ([self.delegate respondsToSelector:@selector(customFallLayout:itemHeightForWidth:atIndexPath:)]) { itemHeight = [self.delegate customFallLayout:self itemHeightForWidth:itemWidth atIndexPath:indexPath]; } } //找出最短的那一列 __block NSNumber *minIndex = @0; [self.maxYDic enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSNumber *obj, BOOL *stop) { if ([self.maxYDic[minIndex] floatValue] > obj.floatValue) { minIndex = key; } }]; //根據最短列的列數計算item的x值 CGFloat itemX = self.sectionInset.left + (self.columnSpacing + itemWidth) * minIndex.integerValue; //item的y值 = 最短列的最大y值 + 行間距 CGFloat itemY = [self.maxYDic[minIndex] floatValue] + self.rowSpacing; //設置attributes的frame attributes.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight); //更新字典中的最大y值 self.maxYDic[minIndex] = @(CGRectGetMaxY(attributes.frame)); return attributes; }
具體實現請看demo,
demo下載地址spa