iOS瀑布流布局

作者: 朱凯奇 | 来源:发表于2016-05-16 16:35 被阅读1443次

    看完千篇一律的UI布局之后,当我们看到瀑布流的布局是不是觉得有种耳目一新的感觉呢?今天我们就说一下如果实现瀑布流,对于瀑布流,现在iOS中总共存在着三种实现方法.

    • 1.实现瀑布流的布局,我们需要计算每一张图片的尺寸大小,然后根据列数布局到我们的UIScrollView上去
    • 2.UITableView实现瀑布流效果,就是每一列都是一个视图.
    • 3.UICollectionView实现瀑布流就是对UICollectionView的UICollectionViewLayout重写
    瀑布流.gif

    实现思想:

    就是把UICollectionView分成三列,由数组保存每一列的高度,然后每次设置UICollectionViewLayoutAttributes的时候,获取最短一列,计算出图片的size,然后添加到最短一列上面。

    具体代码

    自定义布局的实现.h

    #import <UIKit/UIKit.h>
    @class WaterLayout;
    
    //协议
    @protocol WaterLayoutDelegate <NSObject>
    
    //代理方法 返回item的高度
    - (CGFloat)waterLayout:(WaterLayout *)waterLayout heightForRowAtIndexPath:(NSInteger )index itemWidth:(CGFloat )itemWidth;
    
    @end
    
    
    @interface WaterLayout : UICollectionViewLayout
    
    @property (nonatomic,assign) CGFloat columnMargin;//列间距
    
    @property (nonatomic,assign) CGFloat rowMargin;//行间距
    
    @property (nonatomic,assign) UIEdgeInsets edge;//边缘间距
    
    @property (nonatomic,assign) NSInteger columnCount;//列数
    
    @property (nonatomic,assign) id<WaterLayoutDelegate> delegate;//代理
    
    
    @end
    

    自定义布局的实现.m

    
    #import "WaterLayout.h"
    
    @interface WaterLayout ()
    @property (nonatomic,strong) NSMutableArray *attributesArray;   //存放所有cell的布局属性
    @property (nonatomic,strong) NSMutableArray *allColumnMaxYArray; //所有列的高度
    @property (nonatomic,assign) CGFloat contentSizeHeight;//内容的高度
    @end
    @implementation WaterLayout
    
    - (NSMutableArray *)attributesArray {
    
        if (!_attributesArray) {
            _attributesArray = [NSMutableArray array];
        }
    
        return _attributesArray;
    
    }
    
    
    - (NSMutableArray *)allColumnMaxYArray {
        if (!_allColumnMaxYArray) {
            _allColumnMaxYArray  = [NSMutableArray array];
            
        }
        return _allColumnMaxYArray;
    
    
    }
    - (void)prepareLayout {
    
        [super prepareLayout];
        
        self.contentSizeHeight = 0;
    
         //先清空数组
        [self.allColumnMaxYArray removeAllObjects];
        
        for (NSInteger i = 0; i < self.self.columnCount; i++) {
            
            [self.allColumnMaxYArray addObject:@(self.self.edge.top)];
        }
        
        //开始创建每一个cell对应的布局属性
        //一共有多少个cell
        NSInteger count = [self.collectionView numberOfItemsInSection:0];
        
        for (int i = 0; i < count; i++) {
            
            //获取i位置上的索引
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
            
            //获取每个cell的布局属性
            UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
    
            //添加
            [self.attributesArray addObject:attributes];
            
        }
        
    
        
    }
    
    
    /**
     *  这个方法会多次调用
     */
    //cell的排布
    - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
        
     
        return self.attributesArray;
    }
    
    
    
    //indexPath对应cell的布局属性
    - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    
        //为这个cell创建布局属性
        UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
        
        //collectionViewW
        CGFloat collectionViewW = self.collectionView.frame.size.width;
     
        
        //找出高度最短的那一列
         NSInteger column = 0;
        
        //默认第一列的高度最短
         CGFloat minColumnHeight = [self.allColumnMaxYArray[0] doubleValue];
        //遍历数组所有值
        for (NSInteger i = 1; i < self.self.columnCount; i++) {
            
          //取出每一列的高度
            CGFloat columnHeight = [self.allColumnMaxYArray[i] doubleValue];
            //判断高度
            if (minColumnHeight >columnHeight) {
                minColumnHeight = columnHeight;
                //最短列赋值给columnY
                column = i;
            }
            
        }
       
        
        //设置布局
        
        CGFloat w = (collectionViewW - self.edge.left - self.edge.right - (self.columnCount - 1)*self.self.columnMargin) / self.columnCount;
        
        CGFloat x = self.edge.left + column * (w + self.columnMargin);
        
        CGFloat y = minColumnHeight;
        
        //如果不是第一行时
        if (y != self.edge.top) {
            y += self.rowMargin;
        }
        
        //高度由外界决定,通过delegate
        CGFloat h = [self.delegate waterLayout:self heightForRowAtIndexPath:indexPath.row itemWidth:w];
        
        //设置frame
        attributes.frame = CGRectMake(x, y, w, h);
        
        //更新最短列的高度
        self.allColumnMaxYArray[column] = @(CGRectGetMaxY(attributes.frame));
        
        //记录最大高度
        CGFloat columHeight = [self.allColumnMaxYArray[column] doubleValue];
        if (self.contentSizeHeight < columHeight) {
            self.contentSizeHeight = columHeight;
        }
        
        return attributes;
    }
    
    
    //collectionView的ContentSize
    - (CGSize)collectionViewContentSize {
    
     
        //最大高度+self.edge底部高度
        return CGSizeMake(0, self.contentSizeHeight+self.edge.bottom);
    }
    @end
    
    

    外界使用布局方式

    
    #import "ViewController.h"
    #import "WaterLayout.h"
    #import "ShopModel.h"
    #import "ShopViewCell.h"
    @interface ViewController ()<UICollectionViewDataSource,WaterLayoutDelegate>
    @property (nonatomic,strong) NSMutableArray *shopModelArray;
    @end
    
    @implementation ViewController
    
    
    
    - (NSMutableArray *)shopModelArray {
    
        if (!_shopModelArray) {
            _shopModelArray = [NSMutableArray array];
        }
    
    
        return _shopModelArray;
    
    }
    
    
    - (void)setData {
    
    
        NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"1.plist" ofType:nil]];
    
        for (NSDictionary *dic in array) {
            
            ShopModel *shop = [[ShopModel alloc] init];
            
            [shop setValuesForKeysWithDictionary:dic];
            
            [self.shopModelArray addObject:shop];
            
        }
      
    }
    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
       
        //加载数据
        [self setData];
    
        [self setLayout];
        // Do any additional setup after loading the view, typically from a nib.
    }
    
    - (void)setLayout {
    
        WaterLayout *layout = [[WaterLayout alloc] init];
        
        UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
        collectionView.backgroundColor = [UIColor whiteColor];
        
        layout.delegate = self;
        layout.columnCount = 3;
        layout.columnMargin = 10;
        layout.rowMargin = 10;
        layout.edge = UIEdgeInsetsMake(10, 10, 10, 10);
        collectionView.dataSource =self;
        
        [self.view addSubview:collectionView];
        
        
        [collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([ShopViewCell class]) bundle:nil] forCellWithReuseIdentifier:@"shop"];
    }
    
    - (NSInteger )numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
        return 1;
    
    }
    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    
    
        return self.shopModelArray.count;
    
    }
    
    
    
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        ShopViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"shop" forIndexPath:indexPath];
     
        [cell setCellBasicInfoWithModel:self.shopModelArray[indexPath.row]];
     
        return cell;
    }
    
    #pragma mark -----waterLayoutDelegate
    - (CGFloat)waterLayout:(WaterLayout *)waterLayout heightForRowAtIndexPath:(NSInteger)index itemWidth:(CGFloat)itemWidth {
        
        ShopModel *shop = self.shopModelArray[index];
        
        return itemWidth*shop.h/shop.w;
    
    }
    
    
    cell和model我就不展示了,显得代码占得太多了,只要会了思想,相信大家不难实现,在稍加封装,将上面的几个属性,写成代理方法,更加合理些.

    相关文章

      网友评论

      本文标题:iOS瀑布流布局

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