• 自定义UICollectinviewFlowLayout,即实现瀑布流


    如图所示,通过实现不规则的网格分布,来显示出不同的效果。因为集合视图必须要指定布局还可以显示,所以自定义布局就可以实现瀑布流的效果。

    //创建布局对象
        WaterFlowLayout *flowLayout = [[WaterFlowLayout alloc] init];
        
        flowLayout.delegate = self;
        flowLayout.numberOfColumn = 3;
        
        //创建集合视图
        UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:flowLayout];

    因为系统自带的布局有四个方法,分别实现了item大小,分区间隔,最小行间距,item之间的间隙大小

    @protocol UICollectionViewDelegateFlowLayout <UICollectionViewDelegate>
    @optional
    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
    - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
    - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;
    - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;

    所以,自定义FlowLayout,并定义协议,以便定义这些方法。

    @protocol WaterFlowLayoutDelegate <NSObject>
    
    //关键方法,此方法的作用是返回每一个item的size大小
    //数据中原始图片大小
    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
    //分区间隔
    - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
    //得到 item之间的间隙大小
    - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;
    //最小行间距
    - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;
    
    @end
    
    @interface WaterFlowLayout : UICollectionViewLayout
    
    //瀑布流一共多少列
    @property (nonatomic, assign) NSUInteger numberOfColumn;
    
    @property (nonatomic, assign) id<WaterFlowLayoutDelegate>delegate;

    看图可知,最小高的的item,将作为下一列item的起点。

    @interface WaterFlowLayout ()
    
    //存放每一列的高度
    @property (nonatomic, retain) NSMutableArray *columnHeightsArray;
    
    //存放 每一个item的 属性 包含 frame以及下标
    @property (nonatomic, retain) NSMutableArray *attributesArray;
    
    @end
    
    @implementation WaterFlowLayout
    
    //获取最小高度的方法
    - (CGFloat)minHeight
    {
        CGFloat min = 100000;
        for (NSNumber *height in _columnHeightsArray) {
            CGFloat h = [height floatValue];
            if (min > h) {
                min = h;
            }
        }
        return min;
    }
    
    //获取最大值
    - (CGFloat)maxHeight
    {
        CGFloat max = 0;
        for (NSNumber *height in _columnHeightsArray) {
            CGFloat h = [height floatValue];
            if (max < h) {
                max = h;
            }
        }
        return max;
    }
    
    //找到最小高的下标
    - (NSUInteger)indexOfMinHeight
    {
        NSUInteger index = 0;
        for (int i = 0; i < [_columnHeightsArray count]; i ++) {
            CGFloat height = [_columnHeightsArray[i] floatValue];
            if (height == [self minHeight]) {
                index = i;
                return index;
            }
        }
        return index;
    }
    
    //重写父类的布局方法
    - (void)prepareLayout
    {
        [super prepareLayout];
        
        _attributesArray = [[NSMutableArray alloc] init];
        
        _columnHeightsArray = [[NSMutableArray alloc] initWithCapacity:self.numberOfColumn];
        
        //给列高数组里面的对象赋初值
        for (int i = 0; i < self.numberOfColumn; i ++) {
            [_columnHeightsArray addObject:@0.0];
        }
        
        CGFloat totalWidth = self.collectionView.frame.size.width;
        
        //创建 每个item frame中的x、y
        CGFloat x = 0;
        CGFloat y = 0;
        
        NSUInteger itemCount = [self.collectionView numberOfItemsInSection:0];
        
        for (int i = 0; i < itemCount; i ++) {
            //得到集合视图中 列间隙的个数
            NSUInteger numberOfSpace = self.numberOfColumn - 1;
            
            //代理对象执行代理方法,得到 item之间的间隙大小
            CGFloat spaceWidth = [_delegate collectionView:self.collectionView layout:self minimumInteritemSpacingForSectionAtIndex:0];
            
            //求每列的宽度,也就是每个item的width
            CGFloat width = (totalWidth - spaceWidth * numberOfSpace) / self.numberOfColumn;
            
            
            //获取每一个itemSize的大小
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
            
            //数据中原始图片大小
            CGSize imageSize = [_delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
        
            //通过 约分公式得到固定宽之后的高度是多少
            CGFloat height = width * imageSize.height / imageSize.width;
            
            
            UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
            
            //记录每一个item的大小和位置
            attribute.frame = CGRectMake(x, y, width, height);
            
            //数组保存每个item的位置信息
            [_attributesArray addObject:attribute];
            
            NSLog(@"item = %d",i);
            NSLog(@"x = %.2f y = %.2f width = %.2f height = %.2f",x,y,width,height);
            
            //求列高最小的那一列的下标
            NSUInteger minHeightIndex = [self indexOfMinHeight];
            
            //求出最小列的高度
            CGFloat minHeight = [_columnHeightsArray[minHeightIndex] floatValue];
            
            //求出行高
            CGFloat lineHeight = [_delegate collectionView:self.collectionView layout:self minimumLineSpacingForSectionAtIndex:0];
            
            //上一次总的列高 加上 行高 加上新加上的item的height,才是现在这一列的总高度
            //minHeight为最小列现在的高度
            //lineHeight为行间距
            //height为新加的item的高
            _columnHeightsArray[minHeightIndex] = [NSNumber numberWithFloat:minHeight + lineHeight + height];
            
            //重新算最小列高的下标
            minHeightIndex = [self indexOfMinHeight];
            
            //算下一次新加的item的x和y值
            x = (spaceWidth + width) * minHeightIndex;
            
            y = [self minHeight];
        }
    }
    
    //重写这个方法,可以返回集合视图的总高度
    - (CGSize)collectionViewContentSize
    {
        return CGSizeMake(self.collectionView.frame.size.width, [self maxHeight]);
    }
    
    
    - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
    {
        return _attributesArray;
    }

    注意,最后一个方法的实现,即- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect,如果这个方法不写,集合视图是显示不出来的,这个方法是次保存的每个item的信息重新告诉集合视图,进行显示。

  • 相关阅读:
    [LeetCode]Subsets II
    [LeetCode]Subsets
    [LeetCode]Combinations
    [LeetCode]Minimum Window Substring
    [LeetCode]Search a 2D Matrix
    [LeetCode]Edit Distance
    [LeetCode]Simplify Path
    Adaboost算法
    [LeetCode]Text Justification
    31、剑指offer--从1到n整数中1出现次数
  • 原文地址:https://www.cnblogs.com/xueyao/p/5188321.html
Copyright © 2020-2023  润新知