iOS开发 - WaterflowLayout 瀑布流布局

来源:互联网 发布:数据结构与算法面试题 编辑:程序博客网 时间:2024/04/30 05:38

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

瀑布流效果图

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

0 0