美文网首页iOS
自定义的UICollectionViewFlowLayout

自定义的UICollectionViewFlowLayout

作者: CYC666 | 来源:发表于2018-12-18 11:40 被阅读0次

    //=========================================.h=================================

    //  TopBarLayout.h

    //  LOLADFNeverGiveUp

    //

    //  Created by 曹老师 on 2018/12/17.

    //  Copyright © 2018  All rights reserved.

    //

    #import

    NS_ASSUME_NONNULL_BEGIN

    @interface ZoneImageFlowLayout : UICollectionViewFlowLayout

    // item 的行距(默认4.0)

    @property (nonatomic, assign) CGFloat lineSpacing;

    // item 的间距 (默认4.0)

    @property (nonatomic, assign) CGFloat interitemSpacing;

    // header 高度(默认0.0)

    @property (nonatomic, assign) CGFloat headerViewHeight;

    // footer 高度(默认0.0)

    @property (nonatomic, assign) CGFloat footerViewHeight;

    // item 高度 (默认30)

    @property (nonatomic, assign) CGFloat itemHeight;

    // footer 边距缩进(默认UIEdgeInsetsZero)

    @property (nonatomic, assign) UIEdgeInsets footerInset;

    // header 边距缩进(默认UIEdgeInsetsZero)

    @property (nonatomic, assign) UIEdgeInsets headerInset;

    // item 边距缩进(默认UIEdgeInsetsZero)

    @property (nonatomic, assign) UIEdgeInsets itemInset;

    @end

    NS_ASSUME_NONNULL_END

    //============================================.m==========================

    //

    //  TopBarLayout.m

    //  LOLADFNeverGiveUp

    //

    //  Created by 曹老师 on 2018/12/17.

    //  Copyright © 2018  All rights reserved.

    //

    #import "ZoneImageFlowLayout.h"

    @interface ZoneImageFlowLayout()

    /** 总的布局对象数组,包括item,sectionHeader,footerHeader */

    @property (nonatomic, strong) NSMutableArray *attributesArray;

    /** item的布局对象数组 */

    @property (nonatomic, strong) NSMutableArray *itemsattributes;

    /** header的布局对象数组 */

    @property(nonatomic,strong)NSMutableArray*headerAttributes;

    /** footer的布局对象数组 */

    @property(nonatomic,strong)NSMutableArray*footerAttributes;

    /** 计算 collectionview 的内容高度 */

    @property (nonatomic, assign) CGFloat contentHeight;

    /** 计算 collectionview 的内容宽度 */

    @property (nonatomic, assign) CGFloat contentWidth;

    /** collectionview 自身的宽度 */

    @property (nonatomic, assign) CGFloat viewWidth;

    @end

    @implementationZoneImageFlowLayout

    #pragma mark - initialize

    - (instancetype)init {

        if(self= [superinit]) {

            //设置间距的默认值

            self.headerViewHeight = 0.0;

            self.footerViewHeight = 0.0;

            self.interitemSpacing = 4.0;

            self.lineSpacing=4.0;

            self.itemHeight= (kScreenWidth-48) /3;

            self.itemInset = UIEdgeInsetsZero;

            self.headerInset = UIEdgeInsetsZero;

            self.footerInset = UIEdgeInsetsZero;

        }

        return self;

    }

    /** 1、当collectionView布局item时 第一个执行的方法 */

    - (void)prepareLayout {

        /** 重写layout中的方法 首先必须调用父类 */

        [superprepareLayout];

        self.viewWidth =self.collectionView.bounds.size.width -self.itemInset.left -self.itemInset.right;

        //所有内容的布局属性数组

        self.attributesArray = [NSMutableArray array];

        //item的数据模型是2原数组,就是第一层数组包含的是section,第二层是每个section包含的item

        self.itemsattributes = [NSMutableArray array];

        //记录 collectionview 的内容高度

        self.contentHeight =0.0;

        self.contentWidth =0.0;

        /** 获取collectionView 中的item的个数 */

        NSInteger sectionCount = [self.collectionView numberOfSections];

        /** 遍历得到每个item 设置位置信息 */

        for(NSInteger i =0; i < sectionCount; i++) {

            NSInteger itemCount = [self.collectionView numberOfItemsInSection:i];

            for(NSInteger j =0; j < itemCount; j++) {

                [selfsetItemFrameWithIndexPath:[NSIndexPath indexPathForItem:j inSection:i]];

                if( (i == sectionCount -1) && ( j == itemCount -1) ) {

                    //这里是当最后一个 item 的 layoutAttributes 设置完成后如果有设置 footer 就要把 footer 添加到所有 layoutAttributes 数组

    //                if ( [(NSObject *)self.delegate respondsToSelector:@selector(collectionViewDynamicFooterSizeWithIndexPath:)] ) {

    //

    //                    //获取最后一个 item 的 layoutAttributes

    //                    UICollectionViewLayoutAttributes *lastAttributes = self.attributesArray.lastObject;

    //                    //添加 footer 的 layoutAttributes

    //                    [self makeFooterAttributesWithLastItemAttributes:lastAttributes];

    //

    //                    // 获取新添加的 footer 的 layoutAttributes

    //                    UICollectionViewLayoutAttributes *footerAttributes = self.footerAttributes.lastObject;

    //                    //计算总高度

    //                    self.contentHeight = CGRectGetMaxY(footerAttributes.frame) + self.itemInset.bottom;

    //                }

                }

            }

        }

    }

    - (void)setItemFrameWithIndexPath:(NSIndexPath *)indexPath {

        //这里主要是设置一下 item 的初始 frame

        CGFloat x =0.0;

        CGFloat y =0.0;

        CGFloat width = (kScreenWidth -48) /3;

        // 获取数组最后一个 layoutAttributes, 这样方便计算 frame 和 判断是否需要计算新的 section

        UICollectionViewLayoutAttributes *lastAttributes =self.attributesArray.lastObject;

        if( lastAttributes ) {

            //如果数组有值代表不是设置第一个item

            if( lastAttributes.indexPath.section == indexPath.section ) {

                //同一组

                if( (CGRectGetMaxX(lastAttributes.frame) +self.interitemSpacing + width >self.viewWidth) &&

                    (self.scrollDirection == UICollectionViewScrollDirectionVertical)) {

                    //需要换行

                    x =self.itemInset.left;

                    y = CGRectGetMaxY(lastAttributes.frame) +self.lineSpacing;

                }else{

                    //不需要换行

                    x = CGRectGetMaxX(lastAttributes.frame) +self.interitemSpacing;

                    y = CGRectGetMinY(lastAttributes.frame);

                }

            }else{

                //不同一组

                //添加 footer 的布局,内部会判断是否需要添加

                [selfmakeFooterAttributesWithLastItemAttributes:lastAttributes];

                //添加一个新的 section 数组

                [self.itemsattributes addObject:[NSMutableArray array]];

                //这里重新获取最后一个 layoutAttributes 是因为如果加入了 footer 总的 layoutAttributes就会改变

                lastAttributes =self.attributesArray.lastObject;

                //添加 header 的布局,内部会判断是否需要添加

                [selfmakeHeaderAttributesWithIndexPath:indexPath lastItemAttributes:lastAttributes];

                //设置新的 section 的第一个 item 的 frame

                x =self.itemInset.left;

                y = CGRectGetMaxY(lastAttributes.frame) +self.lineSpacing *2+self.headerViewHeight;

            }

        }else{

            //这里是设置第一个section的item

            [self.itemsattributes addObject:[NSMutableArray array]];

            //添加 header 的布局,内部会判断是否需要添加

            [selfmakeHeaderAttributesWithIndexPath:indexPath lastItemAttributes:lastAttributes];

            //这里判断是否有 header, 如果有就获取最后一个 layoutAttributes

            if(self.headerAttributes.count ) {

                lastAttributes =self.attributesArray.lastObject;

            }

            //设置新的 section 的第一个 item 的 frame

            x =self.itemInset.left;

            y = lastAttributes.size.height;

        }

        //设置每一个 item 的 frame

        UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

        /** 添加frame */

        attributes.frame = CGRectMake(x, y, width, width);

        self.contentHeight = CGRectGetMaxY(attributes.frame) +self.lineSpacing;

        self.contentWidth = CGRectGetMaxX(attributes.frame) +self.interitemSpacing;

        /** 保存在数组中 */

        [self.itemsattributes[indexPath.section] addObject:attributes];

        [self.attributesArray addObject:attributes];

    }

    #pragma mark - New Header Or Footer

    - (void)makeHeaderAttributesWithIndexPath:(NSIndexPath *)indexPath lastItemAttributes:(UICollectionViewLayoutAttributes *)attributes {

        //设置第一个section的header

        UICollectionViewLayoutAttributes *headerAttributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader withIndexPath:indexPath];

        CGFloat y = (attributes)?CGRectGetMaxY(attributes.frame) +self.lineSpacing:self.itemInset.top;

        CGFloat headerWidth =  0.0;

        CGFloat headerHeight =  0.0;

    //    if ( [(NSObject *)self.delegate respondsToSelector:@selector(collectionViewDynamicHeaderSizeWithIndexPath:)] ) {

    //        CGSize size = [self.delegate collectionViewDynamicHeaderSizeWithIndexPath:indexPath];

    //

    //        headerWidth = size.width;

    //        headerHeight = size.height;

    //    }else {

    //        headerWidth = kScreenWidth - self.headerInset.left - self.headerInset.right;

    //        headerHeight = self.headerViewHeight;

    //    }

        if( headerHeight >0.0) {

            headerAttributes.frame = CGRectMake(self.headerInset.left, y, headerWidth, headerHeight);

            [self.headerAttributes addObject:headerAttributes];

            [self.attributesArray addObject:headerAttributes];

        }

    }

    - (void)makeFooterAttributesWithLastItemAttributes:(UICollectionViewLayoutAttributes*)attributes {

        UICollectionViewLayoutAttributes *footerAttributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter withIndexPath:attributes.indexPath];

        CGFloatfooterWidth =  0.0;

        CGFloatfooterHeight =  0.0;

    //    if ( [(NSObject *)self.delegate respondsToSelector:@selector(collectionViewDynamicFooterSizeWithIndexPath:)] ) {

    //

    //        CGSize size = [self.delegate collectionViewDynamicFooterSizeWithIndexPath:attributes.indexPath];

    //        footerWidth = size.width;

    //        footerHeight = size.height;

    //    } else {

    //        footerWidth = kScreenWidth - self.footerInset.left - self.footerInset.right;

    //        footerHeight = self.footerViewHeight;

    //    }

        if( footerHeight >0) {

            footerAttributes.frame=CGRectMake(self.footerInset.left,CGRectGetMaxY(attributes.frame) +self.lineSpacing, footerWidth, footerHeight);

            [self.footerAttributesaddObject:footerAttributes];

            [self.attributesArrayaddObject:footerAttributes];

        }

    }

    #pragma mark - 布局

    //这个是返回所有 header, footer, item 属性的回调方法, 一定要实现

    - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {

        return self.attributesArray;

    }

    - (UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath*)indexPath {

        returnself.itemsattributes[indexPath.section][indexPath.item];

    }

    - (UICollectionViewLayoutAttributes*)layoutAttributesForSupplementaryViewOfKind:(NSString*)elementKind atIndexPath:(NSIndexPath*)indexPath {

        if ( [elementKind isEqual: UICollectionElementKindSectionHeader] ) {

            returnself.headerAttributes[indexPath.section];

        }else{

            returnself.footerAttributes[indexPath.section];

        }

    }

    /** 4、设置滚动范围 */

    // 这里可以处理 uicollectionview 内容不够屏幕高度不能滑动的问题,只要把 contentsize.height 设置成比屏幕高度大就可以了

    - (CGSize)collectionViewContentSize {

        if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal) {

            return CGSizeMake(self.contentWidth + self.itemInset.right, 0.0);

        }else{

            return CGSizeMake(0.0, self.contentHeight + self.itemInset.bottom);

        }

    }

    #pragma mark - LazyLoad

    // header 的布局属性数组

    - (NSMutableArray*)headerAttributes {

        if ( !_headerAttributes ) {

            _headerAttributes = [NSMutableArray array];

        }

        return _headerAttributes;

    }

    // footer 的布局属性数组

    - (NSMutableArray*)footerAttributes {

        if ( !_footerAttributes ) {

            _footerAttributes = [NSMutableArray array];

        }

        return _footerAttributes;

    }

    @end

    相关文章

      网友评论

        本文标题:自定义的UICollectionViewFlowLayout

        本文链接:https://www.haomeiwen.com/subject/ocikkqtx.html