iOS開發:瀑布流效果的實現(使用UICollectionView)

iOS開發:瀑布流的實現

圖片描述

效果的實現,主要是對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

相關文章
相關標籤/搜索