UICollectionView自定義流水佈局

UICollectionView自定義流水佈局

重點是重寫系統的layout方法

1.自定義類繼承UICollectionViewFlowLayout

2.UICollectionViewFlowLayout類會自動調用以下方法

-(void)prepareLayout;

layout的佈局準備工作都在這裏面執行

-(CGSize)collectionViewContentSize;

返回的是collectionView的滑動範圍,如果是動態加載的,就不要使用這個方法,可以直接設置每個Item的size,系統會通過size大小自動計算滑動範圍

-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;

返回的是collectionView頁面的佈局,注意此處返回的是一個Attributes的數組


部分代碼:

根據數據計算每個cell的大小

<span style="font-size:14px;">CGFloat columnHeight[self.column];
    for (int i = 0; i < self.column; i++){
        columnHeight[i] = self.sectionInset.top;
    }
    
    CGFloat cellW = (self.collectionView.frame.size.width - (self.column - 1) * self.minimumInteritemSpacing) / self.column;
    

    
    for (int i = 0; i < self.pictures.count; i++){
        Model *model = self.pictures[i];
        CGFloat ratio = model.h.doubleValue / model.w.doubleValue;
        CGFloat cellH = ratio * cellW;
        
        UICollectionViewLayoutAttributes *layout = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
        
        CGFloat cellX = i % self.column * (self.minimumInteritemSpacing + cellW);
        CGFloat cellY = columnHeight[i % self.column];
        layout.frame = CGRectMake(cellX, cellY, cellW, cellH );
        
        //將每個cell的高度存起來
        columnHeight[i % 3] += cellH + self.minimumLineSpacing;
        
        [self.layouts addObject:layout];
 
        
    }
    
    //設置itemSize
    CGFloat maxH = 0;
    for (int i = 0; i < self.column; i++){
        if (maxH < columnHeight[i]) {
            maxH = columnHeight[i];
        }
    }
//    NSLog(@"%f",maxH);
    //計算行數
    CGFloat row = 0;
    if (self.pictures.count % self.column == 0) {
        row = self.pictures.count / self.column;
    }else {
        row = self.pictures.count / self.column + 1;
    }
    CGFloat itemH = (maxH - (self.minimumLineSpacing ) * row) / row;
//    CGFloat itemH = (maxH - self.sectionInset.top) / row;
    //設置ItemSize系統會自動根據size大小計算應該滑動的範圍
    self.itemSize = CGSizeMake(cellW, itemH);</span>

計算的時候要注意行間距和第一行是否留有空隙來計算cell的高度,位置,否則會出現滑動到底的時候cell的底邊和屏幕底邊不會很好貼合


3.添加頭部或底部的視圖

collectionView和tableView一樣,都可以添加頭部和底部視圖,兩者原理一樣,在這裏添加一個底部的

首先實現方法:

-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath

頭部與底部視圖都是通過這個方法實現,可以用kind的值來區分添加的是哪個視圖

頭部:UICollectionElementKindSectionHeader

底部:UICollectionElementKindSectionFooter

然後在自定義的layout類中計算佈局

<span style="font-size:14px;">//添加footer
    UICollectionViewLayoutAttributes *footerAttr = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter withIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
    CGFloat footerH = 50;
    footerAttr.frame = CGRectMake(0, maxH, self.collectionView.frame.size.width, footerH);
[self.layouts addObject:footerAttr];</span>

4.在動態加載cell的時候,可能會遇到類似這種錯誤

<span style="font-size:14px;">*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'layout attributes for supplementary item at index path (<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}) changed from <UICollectionViewLayoutAttributes: 0x7fba41449b90> index path: (<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}); element kind: (UICollectionElementKindSectionFooter); frame = (0 2982.19; 375 50);  to <UICollectionViewLayoutAttributes: 0x7fba4164b760> index path: (<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}); element kind: (UICollectionElementKindSectionFooter); frame = (0 5962.61; 375 50);  without invalidating the layout'</span>

這個就是因爲再一次加載layout時,layout的數據不對了,我們的數組裏面一共存放了兩次的佈局,系統不能很好的匹配這些屬性了

這個問題有兩種解決辦法:

(1)在每次計算屬性時都創建一個局部的數組,將每次的數據放在這裏,最後再將其賦給全局的佈局屬性數組即可

(2)創建兩個全局屬性的數組,每次都將其第一個數組,最後將第一個數組裏面的數據放入第二個數組裏,再將第一個數組數據清空(道理與第一個相同,不過賦值時記得用深拷貝,否則清空會兩個數組都爲空)

    self.returnSize =self.layouts.mutableCopy;

    [self.returnSizesetArray:self.layouts.copy];

    [self.layoutsremoveAllObjects];



注:此方法都是在storyboard上做的

附項目源碼:http://download.csdn.net/detail/aa603020460/9387678








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章