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








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值