• WaterflowLayout 瀑布流布局


    Model Data

    @interface Shop : NSObject
    @property (nonatomic, assign) CGFloat w;
    @property (nonatomic, assign) CGFloat h;
    @property (nonatomic, copy) NSString *img;
    @property (nonatomic, copy) NSString *price;
    @end

    define cell

    @class Shop;
    @interface ShopCell : UICollectionViewCell
    @property (nonatomic, strong) Shop *shop;
    @end
    
    #import "ShopCell.h"
    #import "Shop.h"
    #import "UIImageView+WebCache.h"
    
    @interface ShopCell()
    @property (weak, nonatomic) IBOutlet UIImageView *imageView;
    @property (weak, nonatomic) IBOutlet UILabel *priceLabel;
    @end
    
    @implementation ShopCell
    
    - (void)setShop:(Shop *)shop
    {
        _shop = shop;
    
        // 1.图片
        [self.imageView sd_setImageWithURL:[NSURL URLWithString:shop.img] placeholderImage:[UIImage imageNamed:@"loading"]];
    
        // 2.价格
        self.priceLabel.text = shop.price;
    }
    @end

    xib 
    这里写图片描述

    WaterflowLayout 瀑布流布局

    @class WaterflowLayout;
    
    @protocol WaterflowLayoutDelegate <NSObject>
    - (CGFloat)waterflowLayout:(WaterflowLayout *)waterflowLayout heightForWidth:(CGFloat)width atIndexPath:(NSIndexPath *)indexPath;
    @end
    
    @interface WaterflowLayout : UICollectionViewLayout
    @property (nonatomic, assign) UIEdgeInsets sectionInset;
    /** 每一列之间的间距 */
    @property (nonatomic, assign) CGFloat columnMargin;
    /** 每一行之间的间距 */
    @property (nonatomic, assign) CGFloat rowMargin;
    /** 显示多少列 */
    @property (nonatomic, assign) int columnsCount;
    
    @property (nonatomic, weak) id<WaterflowLayoutDelegate> delegate;
    
    @end
    
    @interface WaterflowLayout();
    /** 这个字典用来存储每一列最大的Y值(每一列的高度) */
    @property (nonatomic, strong) NSMutableDictionary *maxYDict;
    
    /** 存放所有的布局属性 */
    @property (nonatomic, strong) NSMutableArray *attrsArray;
    @end
    
    @implementation WaterflowLayout
    
    - (NSMutableDictionary *)maxYDict
    {
        if (!_maxYDict) {
            self.maxYDict = [[NSMutableDictionary alloc] init];
        }
        return _maxYDict;
    }
    
    - (NSMutableArray *)attrsArray
    {
        if (!_attrsArray) {
            self.attrsArray = [[NSMutableArray alloc] init];
        }
        return _attrsArray;
    }
    
    - (instancetype)init
    {
        if (self = [super init]) {
            self.columnMargin = 10;
            self.rowMargin = 10;
            self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
            self.columnsCount = 3;
        }
        return self;
    }
    
    - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
    {
        return YES;
    }
    
    /**
     *  每次布局之前的准备
     */
    - (void)prepareLayout
    {
        [super prepareLayout];
    
        // 1.清空最大的Y值
        for (int i = 0; i<self.columnsCount; i++) {
            NSString *column = [NSString stringWithFormat:@"%d", i];
            self.maxYDict[column] = @(self.sectionInset.top);
        }
    
        // 2.计算所有cell的属性
        [self.attrsArray removeAllObjects];
        NSInteger count = [self.collectionView numberOfItemsInSection:0];
        for (int i = 0; i<count; i++) {
            UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
            [self.attrsArray addObject:attrs];
        }
    }
    
    /**
     *  返回所有的尺寸
     */
    - (CGSize)collectionViewContentSize
    {
        __block NSString *maxColumn = @"0";
        [self.maxYDict enumerateKeysAndObjectsUsingBlock:^(NSString *column, NSNumber *maxY, BOOL *stop) {
            if ([maxY floatValue] > [self.maxYDict[maxColumn] floatValue]) {
                maxColumn = column;
            }
        }];
        return CGSizeMake(0, [self.maxYDict[maxColumn] floatValue] + self.sectionInset.bottom);
    }
    
    /**
     *  返回indexPath这个位置Item的布局属性
     */
    - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        // 假设最短的那一列的第0列
        __block NSString *minColumn = @"0";
        // 找出最短的那一列
        [self.maxYDict enumerateKeysAndObjectsUsingBlock:^(NSString *column, NSNumber *maxY, BOOL *stop) {
            if ([maxY floatValue] < [self.maxYDict[minColumn] floatValue]) {
                minColumn = column;
            }
        }];
    
        // 计算尺寸
        CGFloat width = (self.collectionView.frame.size.width - self.sectionInset.left - self.sectionInset.right - (self.columnsCount - 1) * self.columnMargin)/self.columnsCount;
        CGFloat height = [self.delegate waterflowLayout:self heightForWidth:width atIndexPath:indexPath];
    
        // 计算位置
        CGFloat x = self.sectionInset.left + (width + self.columnMargin) * [minColumn intValue];
        CGFloat y = [self.maxYDict[minColumn] floatValue] + self.rowMargin;
    
        // 更新这一列的最大Y值
        self.maxYDict[minColumn] = @(y + height);
    
        // 创建属性
        UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
        attrs.frame = CGRectMake(x, y, width, height);
        return attrs;
    }
    
    /**
     *  返回rect范围内的布局属性
     */
    - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
    {
        return self.attrsArray;
    }
    
    @end
    

    控制器 ViewController

    #import "ViewController.h"
    #import "WaterflowLayout.h"
    #import "MJExtension.h"
    #import "Shop.h"
    #import "ShopCell.h"
    #import "MJRefresh.h"
    
    @interface ViewController () <UICollectionViewDataSource, UICollectionViewDelegate, WaterflowLayoutDelegate>
    @property (nonatomic, weak) UICollectionView *collectionView;
    @property (nonatomic, strong) NSMutableArray *shops;
    @end
    
    @implementation ViewController
    
    - (NSMutableArray *)shops
    {
        if (_shops == nil) {
            self.shops = [NSMutableArray array];
        }
        return _shops;
    }
    
    static NSString *const ID = @"shop";
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        // 1.初始化数据
        NSArray *shopArray = [Shop objectArrayWithFilename:@"1.plist"];
        [self.shops addObjectsFromArray:shopArray];
    
    
        WaterflowLayout *layout = [[WaterflowLayout alloc] init];
        layout.delegate = self;
    //    layout.sectionInset = UIEdgeInsetsMake(100, 20, 40, 30);
    //    layout.columnMargin = 20;
    //    layout.rowMargin = 30;
    //    layout.columnsCount = 4;
    
        // 2.创建UICollectionView
        UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
        collectionView.backgroundColor = [UIColor whiteColor];
        collectionView.dataSource = self;
        collectionView.delegate = self;
        [collectionView registerNib:[UINib nibWithNibName:@"ShopCell" bundle:nil] forCellWithReuseIdentifier:ID];
        [self.view addSubview:collectionView];
        self.collectionView = collectionView;
    
        // 3.增加刷新控件
        [self.collectionView addFooterWithTarget:self action:@selector(loadMoreShops)];
    }
    
    - (void)loadMoreShops
    {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSArray *shopArray = [Shop objectArrayWithFilename:@"1.plist"];
            [self.shops addObjectsFromArray:shopArray];
            [self.collectionView reloadData];
            [self.collectionView footerEndRefreshing];
        });
    }
    
    #pragma mark - <WaterflowLayoutDelegate>
    - (CGFloat)waterflowLayout:(WaterflowLayout *)waterflowLayout heightForWidth:(CGFloat)width atIndexPath:(NSIndexPath *)indexPath
    {
        Shop *shop = self.shops[indexPath.item];
        return shop.h / shop.w * width;
    }
    
    #pragma mark - <UICollectionViewDataSource>
    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
    {
        return self.shops.count;
    }
    
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        ShopCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath];
        cell.shop = self.shops[indexPath.item];
        return cell;
    }
    
    @end

    瀑布流效果图

    这里写图片描述这里写图片描述

  • 相关阅读:
    《孙子兵法》(前六篇)读书笔记
    写代码的指导思想:如何写出易测、清晰、健壮的牢固代码
    如何从业务代码中抽离出可复用的微组件
    碎碎念集萃二八
    订单同步工程标准化改造事记
    代码的味道
    批量导出51电子发票的pdf文件
    LODOP具体的分类的简短问答
    lodop打印透明图简短问答
    LODOP打印公章的白色透明2
  • 原文地址:https://www.cnblogs.com/crash-wu/p/4923626.html
Copyright © 2020-2023  润新知