iOS UICollectionView瀑布流


一、UICollectionViewLayout基礎(chǔ)知識

  • 如果要自定義UICollectionViewLayout,需要實(shí)現(xiàn)以下幾個(gè)方法,按初始化layout后,系統(tǒng)執(zhí)行順序排列:
// 初始化layout后自動(dòng)調(diào)動(dòng),可以在該方法中初始化一些自定義的變量參數(shù)
  - (void)prepareLayout;
// 設(shè)置UICollectionView的內(nèi)容大小,道理與UIScrollView的contentSize類似
  - (CGSize)collectionViewContentSize;
// 初始Layout外觀,返回所有的布局屬性
  - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect;
// 根據(jù)不同的indexPath,給出布局 
  - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;

二、瀑布流布局

  • 邏輯與原理
邏輯其實(shí)很簡單,就是給出每一個(gè)cell的坐標(biāo)。想要定位一個(gè)控件,需要CGRectMake四個(gè)參數(shù):

y : 首先我們看到的這個(gè)demo是兩列的,所以肯定有兩個(gè)Y軸起始點(diǎn),分為左側(cè)和右側(cè)。
x : 然后除Y軸不同外,左側(cè)和右側(cè)的X軸也不相同。
width : 關(guān)于width我們可以通過一行兩列,然后每一個(gè)cell的間距來得到。
height: height是在collectionView中定義的,layout獲得不到,所以我們選擇用代理,在collectionView中設(shè)置。
  • 需要的定義的變量
@property (assign, nonatomic) CGFloat   leftY;       // 左側(cè)起始Y軸
@property (assign, nonatomic) CGFloat   rightY;      // 右側(cè)起始Y軸
@property (assign, nonatomic) NSInteger cellCount;   // cell個(gè)數(shù)
@property (assign, nonatomic) CGFloat   itemWidth;   // cell寬度
@property (assign, nonatomic) CGFloat   insert;      // 間距
  • 代理的定義
@class WaterfallFlowLayout;

@protocol WaterfallFlowLayoutDelegate <NSObject>

@required
- (CGSize)collectionView:(UICollectionView *)collectionView collectionViewLayout:(sWaterfallFlowLayout *)collectionViewLayout sizeOfItemAtIndexPath:(NSIndexPath *)indexPath;
@end
  • 布局方法的實(shí)現(xiàn)
/**
 *  初始化layout后自動(dòng)調(diào)動(dòng),可以在該方法中初始化一些自定義的變量參數(shù)
 */
- (void)prepareLayout {
    [super prepareLayout];
    
    // 初始化參數(shù)
    _cellCount = [self.collectionView numberOfItemsInSection:0]; // cell個(gè)數(shù),直接從collectionView中獲得
    _insert = 10; // 設(shè)置間距
    _itemWidth = (SCREEN_WIDTH - 3 * _insert) / 2; // cell寬度
}

/**
 *  設(shè)置UICollectionView的內(nèi)容大小,道理與UIScrollView的contentSize類似
 *  @return 返回設(shè)置的UICollectionView的內(nèi)容大小
 */
- (CGSize)collectionViewContentSize {
    
    return CGSizeMake(SCREEN_WIDTH, MAX(_leftY, _rightY));
}

/**
 *  初始Layout外觀
 *  @param rect 所有元素的布局屬性
 *  @return 所有元素的布局
 */
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    
    _leftY = _insert; // 左邊起始Y軸
    _rightY = _insert; // 右邊起始Y軸
    
    NSMutableArray *attributes = [[NSMutableArray alloc] init];
    
    for (int i = 0; i < self.cellCount; i ++) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
        [attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
    }
    return attributes;
}

/**
 *  根據(jù)不同的indexPath,給出布局
 *  @param indexPath
 *  @return 
 */
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    
    // 獲取代理中返回的每一個(gè)cell的大小
    CGSize itemSize = [self.delegate collectionView:self.collectionView collectionViewLayout:self sizeOfItemAtIndexPath:indexPath];
    
    // 防止代理中給的size.width大于(或小于)layout中定義的width,所以等比例縮放size
    CGFloat itemHeight = floorf(itemSize.height * self.itemWidth / itemSize.width);
    
    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
    // 判斷當(dāng)前的item應(yīng)該在左側(cè)還是右側(cè)
    BOOL isLeft = _leftY < _rightY;
    
    if (isLeft) {
        CGFloat x = _insert;
        attributes.frame = CGRectMake(x, _leftY, _itemWidth, itemHeight);
        _leftY += itemHeight + _insert; // 設(shè)置新的Y起點(diǎn)
    } else {
        CGFloat x = _itemWidth + 2 * _insert;
        attributes.frame = CGRectMake(x, _rightY, _itemWidth, itemHeight);
        _rightY += itemHeight + _insert;
    }
    
    return attributes;
}

Demo地址

https://github.com/shawenlx/WaterfallFlowCollection

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

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