CollectionView瀑布流

簡單的瀑布流實現(xiàn)。github地址

image

各種不規(guī)則的布局都可以利用UICollectionVIewLayout來實現(xiàn),因此我們要自定義一個layout來繼承系統(tǒng)的UICollectionViewLayout,所有工作都在這個類中進(jìn)行。

思路:
1、從上往下,哪一列最短,就把下一個item放在哪一列,因此我們需要定義一個字典來記錄每一列的最大y值

2、每一個item都有一個attributes,因此定義一個數(shù)組來保存每一個item的attributes

image

下面是具體步驟:
1.初始化需要用的總列數(shù)、列間距、行間距、距離collectionView的上下左右距離

//總列數(shù)
@property(nonatomic, assign) NSInteger columnCount;
//列間距
@property(nonatomic, assign) NSInteger columnSpacing;
//行間距
@property(nonatomic, assign) NSInteger rowSpacing;
//section到collectionView的邊距
@property (nonatomic, assign) UIEdgeInsets sectionInset;
//保存每一列最大y值的數(shù)組
@property(nonatomic, strong) NSMutableDictionary * maxYDic;
//保存每一個item的attributes的數(shù)組
@property(nonatomic, strong) NSMutableArray * attributesArray;

需要重寫的4個方法:

  • (void)prepareLayout;
    系統(tǒng)準(zhǔn)備在item進(jìn)行布局前會調(diào)用這個方法,我們重寫這個方法可以在方法里面預(yù)先設(shè)置好需要用到的變量屬性等。
  • (CGSize)collectionViewContentSize;
    由于collectionView將item的布局任務(wù)委托給了layout對象,那么滾動區(qū)域的大小對于它而言是不可知的。自定義布局必須在這個方法里面計算出顯示內(nèi)容的大小,包括supplementaryView和decorationView在內(nèi)
  • (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
    我們可以在這個方法中創(chuàng)建并且返回特別定制的布局屬性
  • (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect;
    核心方法。collectionView調(diào)用這個方法并將自身坐標(biāo)中的矩形傳過來,這個巨型代表著當(dāng)前collectionView的可視范圍,我們需要在這個方法中返回一個包括UICollectionViewLayoutAttributes對象的數(shù)組,這個布局屬性對象決定了當(dāng)前顯示的item的大小、層次、可視屬性在內(nèi)的布局屬性
- (void)prepareLayout 
{    
  [super prepareLayout];

    //初始化字典。有幾列就有幾個鍵值對 value為列的y值

    for (int i = 0; i < self.columnCount; i ++) {

        self.maxYDic[@(i)] = @(self.sectionInset.top);

    }
    //根據(jù)collectionView獲取總共有多少個item
    NSInteger itemCount = [self.collectionView numberOfItemsInSection:0];

    [self.attributesArray removeAllObjects];
    //為每一個item創(chuàng)建一個attributes并存入數(shù)組
    for (int i = 0; i < itemCount; i ++) {
        UICollectionViewLayoutAttributes * attributes = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
        
        [self.attributesArray addObject:attributes];
    }
    
}
//遍歷字典,找出最長的那一列
    [self.maxYDic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        if ([self.maxYDic[maxIndex] floatValue] < [obj floatValue]) {
            maxIndex = key;
        }
    }];
//用來設(shè)置每個item的attributes
CGFloat itemWidth = (collectionViewWidth - self.sectionInset.left - self.sectionInset.right - (self.columnCount - 1) * self.columnSpacing) / self.columnCount;
    
    CGFloat itemHeight = 0;
//通過代理或者block將圖片的寬度傳出去,然后根據(jù)比例獲得圖片的高度
    if (self.itemHeightBlock){
        itemHeight = self.itemHeightBlock(itemWidth,indexPath);
    }else{
        if ([self.delegate respondsToSelector:@selector(waterfallLayout:itemHeightForWidth:atIndexPath:)]) {
            itemHeight = [self.delegate waterfallLayout:self itemHeightForWidth:itemWidth atIndexPath:indexPath];
        }
    }

CGFloat itemX = self.sectionInset.left + (self.columnSpacing + itemWidth) * minIndex.integerValue;
    
    //item的y值 = 最短列的最大y值+ 行間距
    CGFloat itemY = [self.maxYDic[minIndex] floatValue] + self.rowSpacing;

BUG:在重寫UICollectionViewCell的時候,如果通過代碼創(chuàng)建,然后在initWithFrame里面添加一個imageView,那么我怎么設(shè)置frame都有問題,但是通過xib創(chuàng)建則是沒有問題的,如果有朋友知道希望告知。

具體實現(xiàn)方法還可以參考這篇文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容