博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS collectionView实现瀑布流
阅读量:4289 次
发布时间:2019-05-27

本文共 13145 字,大约阅读时间需要 43 分钟。

1.模型:需要有宽高来控制cell的高度, 

#import 
NS_ASSUME_NONNULL_BEGIN@interface LYBDiscoveryRecomendcollectionviewmodel : NSObject@property(nonatomic,assign)NSInteger h;@property(nonatomic,assign)NSInteger w;@endNS_ASSUME_NONNULL_END#import "LYBDiscoveryRecomendcollectionviewmodel.h"@implementation LYBDiscoveryRecomendcollectionviewmodel@end

2.

#import 
NS_ASSUME_NONNULL_BEGIN@interface LYBDiscoveryRecomandcollectionview : UIView@endNS_ASSUME_NONNULL_END#import "LYBDiscoveryRecomandcollectionview.h"#import "LYBDiscoveryRecomandWaterFlowLayout.h"#import "LYBDiscoveryrecommandcollectionviewcell.h"#import "LYBDiscoveryRecomendcollectionviewmodel.h"@interface LYBDiscoveryRecomandcollectionview()
@property(nonatomic,strong)NSMutableArray *modelarr;@endstatic NSString *const recommandidenfier=@"recommandidenfier";@implementation LYBDiscoveryRecomandcollectionview-(NSMutableArray *)modelarr{ if(nil==_modelarr){ _modelarr=[[NSMutableArray alloc]init]; } return _modelarr;}-(instancetype)initWithFrame:(CGRect)frame{ if(self=[super initWithFrame:frame]){ [self initViews]; [self initData]; } return self;}-(void)initData{ for (int i=0; i<20; i++) { LYBDiscoveryRecomendcollectionviewmodel *model=[[LYBDiscoveryRecomendcollectionviewmodel alloc]init]; model.h=random()/50+i; model.w=random()/50+i; [self.modelarr addObject:model]; } }-(void)initViews{ LYBDiscoveryRecomandWaterFlowLayout *flowlayout=[[LYBDiscoveryRecomandWaterFlowLayout alloc]init]; flowlayout.delegate=self; flowlayout.itemSize=CGSizeMake((WIDTH-40*TRANSH)/2,(WIDTH-40*TRANSH)/2); UICollectionView *coll=[[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, WIDTH, HEIGHT-BottomHeight-TopSpaceHigh-NAVH*TRANSH) collectionViewLayout:flowlayout]; [coll registerClass:[LYBDiscoveryrecommandcollectionviewcell class] forCellWithReuseIdentifier:recommandidenfier]; coll.showsVerticalScrollIndicator=NO; coll.backgroundColor=[UIColor whiteColor]; coll.dataSource=self; coll.delegate=self; [self addSubview:coll];}-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{ return 1;}- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return self.modelarr.count;}-(__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ LYBDiscoveryrecommandcollectionviewcell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:recommandidenfier forIndexPath:indexPath]; cell.backgroundColor=[UIColor systemPinkColor]; return cell;}-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{ SLog(@"xuanzhogn");}- (CGFloat)LYBDiscoveryRecomandWaterFlowLayout:(LYBDiscoveryRecomandWaterFlowLayout *)LYBDiscoveryRecomandWaterFlowLayout withIndexPath:(NSIndexPath *)indexPath andItemWidth:(CGFloat)width { LYBDiscoveryRecomendcollectionviewmodel *model = self.modelarr[indexPath.item];return width * model.h / model.w;}@end

3.自定义flowlayout

#import 
@class LYBDiscoveryRecomandWaterFlowLayout;NS_ASSUME_NONNULL_BEGIN@protocol LYBDiscoveryRecomandWaterFlowLayoutdelegate
-(CGFloat)LYBDiscoveryRecomandWaterFlowLayout:(LYBDiscoveryRecomandWaterFlowLayout*)LYBDiscoveryRecomandWaterFlowLayout withIndexPath:(NSIndexPath *)indexPath andItemWidth:(CGFloat)itemWidth;@end@interface LYBDiscoveryRecomandWaterFlowLayout : UICollectionViewFlowLayout@property(nonatomic,weak)id
delegate;@endNS_ASSUME_NONNULL_END#import "LYBDiscoveryRecomandWaterFlowLayout.h"@interface LYBDiscoveryRecomandWaterFlowLayout()// 保存每一列最大的Y值@property (nonatomic,strong)NSMutableArray *maxYArray;@end// 最大列数static NSInteger maxColumn =2;@implementation LYBDiscoveryRecomandWaterFlowLayout- (NSMutableArray *)maxYArray { if (nil ==_maxYArray) {_maxYArray = [NSMutableArray array];}return _maxYArray;}-(instancetype)init {if (self = [super init]) {}return self;}//准备布局的时候调用 ,当布局刷新(改变)- (void)prepareLayout {[super prepareLayout];}//当可见范围发生变化的时候, 就会重新布局- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {return YES;}#pragma mark -#pragma mark - 反回的是每一个cell的属性// 对每一个cell的属性进行设置, frame(x,y,width, height)- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {// 确定最大的列数//    NSInteger maxColumn = 3;// 确定行间距, 列间距 CGFloat columnMargin = 10;CGFloat rowMargin = 10;// 确定组的内间距UIEdgeInsets sectionInsets = UIEdgeInsetsMake(10, 10, 10, 10);// 取出collectionView 的 sizeCGSize collectionViewSize = self.collectionView.frame.size;// 确定cell 的宽度CGFloat itemWidth = (collectionViewSize.width - sectionInsets.left - sectionInsets.right - (maxColumn - 1) * columnMargin) / maxColumn; // 确定cell的高度// 取出对应到 indexPath.item , imageArray 的对象//    ShopModel *shopModel = _imageArray[indexPath.row];// itemW/itemH = w/h//    CGFloat itemHeight = itemWidth * shopModel.h / shopModel.w; CGFloat itemHeight = [self.delegate LYBDiscoveryRecomandWaterFlowLayout:self withIndexPath:indexPath andItemWidth:itemWidth];// 确定cell 的 x和  y// 找到 最短的最大Y值CGFloat minMaxY = [self.maxYArray[0]doubleValue];// 定义 最短的列NSInteger minColumn = 0;for (int i =1; i
arrayY) {// 确定最短的最大Y值minMaxY = arrayY; minColumn = i;}}CGFloat itemX = minColumn * itemWidth + minColumn * columnMargin + sectionInsets.left;CGFloat itemY = minMaxY + rowMargin; UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];attributes.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight); // 记录 最大Y值self.maxYArray[minColumn] =@(CGRectGetMaxY(attributes.frame)); return attributes;}#pragma mark -#pragma mark -  反回可见区域的cell属性- (NSArray
*)layoutAttributesForElementsInRect:(CGRect)rect {// 在每次调用这个方法的时候, 最好把 maxYArray 给清空掉[self.maxYArray removeAllObjects];// 对数组做初始化for (int i =0; i < maxColumn; i++) {[self.maxYArray addObject:@0];}// 实例化一个可变数组NSMutableArray *itemArray = [NSMutableArray array];// 取出当前有多少个cell, 反回第0组有多少个cellNSInteger itemCount = [self.collectionView numberOfItemsInSection:0];for (int i =0; i < itemCount; i++) { // 创建一个 indexPath NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];// 调用 layoutAttributesForItemAtIndexPath: 返回是对应到indexPath 中cell的属性UICollectionViewLayoutAttributes *attri = [self layoutAttributesForItemAtIndexPath:indexPath];// 把cell的属性放到 可变数组中[itemArray addObject:attri]; }return itemArray;}- (CGSize)collectionViewContentSize { CGFloat maxY = 0; if (self.maxYArray.count) { maxY = [self.maxYArray[0]doubleValue]; for (int i =1; i

4.

#import 
#import "LYBDiscoveryRecomendcollectionviewmodel.h"NS_ASSUME_NONNULL_BEGIN@interface LYBDiscoveryrecommandcollectionviewcell : UICollectionViewCell@property(nonatomic,strong)LYBDiscoveryRecomendcollectionviewmodel *model;@endNS_ASSUME_NONNULL_END#import "LYBDiscoveryrecommandcollectionviewcell.h"@interface LYBDiscoveryrecommandcollectionviewcell()@end@implementation LYBDiscoveryrecommandcollectionviewcell-(instancetype)initWithFrame:(CGRect)frame{ if(self =[super initWithFrame:frame]){ [self initviews]; } return self;}-(void)initviews{ self.layer.borderColor=[UIColor blueColor].CGColor; self.layer.borderWidth=3;}-(void)setModel:(LYBDiscoveryRecomendcollectionviewmodel *)model{ }@end

 

#import "WaterFlowLayout.h"

#import "ShopModel.h"

@interface WaterFlowLayout()

// 保存每一列最大的Y值

@property (nonatomic,strong)NSMutableArray *maxYArray;

@end

// 最大列数

static    NSInteger maxColumn =3;

@implementation WaterFlowLayout

- (NSMutableArray *)maxYArray {

    if (nil ==_maxYArray) {

        _maxYArray = [NSMutableArray array];

    }

    return_maxYArray;

}

- (instancetype)init {

    if (self = [superinit]) {

     }

    return self;

}

//准备布局的时候调用 ,当布局刷新(改变)

- (void)prepareLayout {

    [superprepareLayout];

}

//当可见范围发生变化的时候, 就会重新布局

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {

    returnYES;

}

#pragma mark -

#pragma mark - 反回的是每一个cell的属性

// 对每一个cell的属性进行设置, frame(x,y,width, height)

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

    // 确定最大的列数

//    NSInteger maxColumn = 3;

// 确定行间距, 列间距

    CGFloat columnMargin = 10;

    CGFloat rowMargin = 10;

// 确定组的内间距

    UIEdgeInsets sectionInsets = UIEdgeInsetsMake(10, 10, 10, 10);

// 取出collectionView 的 size

    CGSize collectionViewSize = self.collectionView.frame.size;

// 确定cell 的宽度

    CGFloat itemWidth = (collectionViewSize.width - sectionInsets.left - sectionInsets.right - (maxColumn - 1) * columnMargin) / maxColumn;

  // 确定cell的高度

#warning 计算cell的高度待定

    // 取出对应到 indexPath.item , imageArray 的对象

//    ShopModel *shopModel = _imageArray[indexPath.row];

    // itemW/itemH = w/h

//    CGFloat itemHeight = itemWidth * shopModel.h / shopModel.w;

  CGFloat itemHeight = [self.delegate waterFlowLayout:self withIndexPath:indexPath andItemWidth:itemWidth];

// 确定cell 的 x和  y

#warning x, y 待计算

  // 找到 最短的最大Y值

    CGFloat minMaxY = [self.maxYArray[0]doubleValue];

   // 定义 最短的列

    NSInteger minColumn = 0;

for (int i =1; i <maxColumn; i++) {

        // 取出数组中的Y值

        CGFloat arrayY = [self.maxYArray[i]doubleValue];

   if (minMaxY > arrayY) {

            // 确定最短的最大Y

            minMaxY = arrayY;

        minColumn = i;

        }

    }

 CGFloat itemX = minColumn * itemWidth + minColumn * columnMargin + sectionInsets.left;

   CGFloat itemY = minMaxY + rowMargin;

  UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

  attributes.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight);

   // 记录 最大Y值

    self.maxYArray[minColumn] =@(CGRectGetMaxY(attributes.frame));

  return attributes;

}

#pragma mark -  反回可见区域的cell属性

- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {

    // 在每次调用这个方法的时候, 最好把 maxYArray 给清空掉

    [self.maxYArray removeAllObjects];

    

    // 对数组做初始化

    for (int i =0; i < maxColumn; i++) {

        [self.maxYArray addObject:@0];

    }

    

    // 实例化一个可变数组

    NSMutableArray *itemArray = [NSMutableArray array];

    

    // 取出当前有多少个cell, 反回第0组有多少个cell

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

  for (int i =0; i < itemCount; i++) {

        // 创建一个 indexPath

        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:iinSection:0];

   // 调用 layoutAttributesForItemAtIndexPath: 返回是对应到indexPath 中cell的属性

        UICollectionViewLayoutAttributes *attri = [self layoutAttributesForItemAtIndexPath:indexPath];

          // 把cell的属性放到 可变数组中

        [itemArray addObject:attri];

    }

    return itemArray;

}

- (CGSize)collectionViewContentSize {

   CGFloat maxY = 0;

  if (self.maxYArray.count) {

        maxY = [self.maxYArray[0]doubleValue];

     for (int i =1; i <maxColumn; i++) {

            CGFloat arryY = [self.maxYArray[i]doubleValue];

           if (maxY < arryY) {

                maxY = arryY;

            }

        }

    }

    return CGSizeMake(0, maxY +10);

}

@end

========================================================
 

#import "ViewController.h"

#import "ShopCell.h"

#import "WaterFlowLayout.h"

#import "ShopModel.h"

@interface ViewController ()<UICollectionViewDataSource,WaterFlowLayoutDelegate>

@property (nonatomic,strong)NSArray *dataArray;

@end

static NSString *identifier =@"shopCell";

@implementation ViewController

#pragma mark -

#pragma mark -  懒加载

- (NSArray *)dataArray {

    if (nil ==_dataArray) {

  //

        NSString *path = [[NSBundle mainBundle]pathForResource:@"shop.plist" ofType:nil];

     //

        NSArray *tempArray = [NSArray arrayWithContentsOfFile:path];

       //

        NSMutableArray *mutable = [NSMutableArray array];

     //

        for (NSDictionary *dictin tempArray) {

            ShopModel *shopModel = [ShopModel shopModelWithDict:dict];

                 [mutable addObject:shopModel];

        }

        _dataArray = mutable;

    }

    return_dataArray;

}

- (void)viewDidLoad {

    [superviewDidLoad];

  // 1. 实例化一个流水布局

    WaterFlowLayout *flowlayout = [[WaterFlowLayout alloc]init];

// 赋值

//    flowlayout.imageArray = self.dataArray;

    flowlayout.delegate = self;

// 2. 实力化一个collectionView

    UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:flowlayout];

  // 3. 设置数据源代理

    collectionView.dataSource = self;

   // 4. 注册一个cell

    UINib *nib = [UINibnibWithNibName:@"ShopCell"bundle:nil];

      [collectionView registerNib:nib forCellWithReuseIdentifier:identifier];

     // 5. collectionView 添加到控制器的view上

    [self.viewaddSubview:collectionView];

}

// 组

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {

    return 1;

}

// 行

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {

    return self.dataArray.count;

}

// 内

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

    ShopCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];

  cell.backgroundColor = [UIColorredColor];

  cell.shopModel = self.dataArray[indexPath.item];

    //cell的contentView的属性是只读的,不能改变,但是可以在contentView上添加子控件

    return cell;

}

#pragma mark -

#pragma mark - 通过代理方法返回 item的高度

- (CGFloat)waterFlowLayout:(WaterFlowLayout *)waterFlowLayout withIndexPath:(NSIndexPath *)indexPath andItemWidth:(CGFloat)width {

    ShopModel *shopModel = self.dataArray[indexPath.item];

     return width * shopModel.h / shopModel.w;

}

@end

 

转载地址:http://qqlgi.baihongyu.com/

你可能感兴趣的文章
用递归方法建立二叉树
查看>>
用递归方法对二叉树进行先序、中序和后序遍历
查看>>
翻转二叉树
查看>>
逆序链表
查看>>
epoll 使用详解
查看>>
stl 中 set容器用法
查看>>
有序数组求交集
查看>>
文字常量区与栈
查看>>
非阻塞connect 编写方法
查看>>
epoll 边沿触发
查看>>
String类 默认生成的函数
查看>>
Linux 软连接与硬链接
查看>>
视音频数据处理入门:H.264视频码流解析
查看>>
视音频数据处理入门:AAC音频码流解析
查看>>
视音频数据处理入门:UDP-RTP协议解析
查看>>
视音频数据处理入门:FLV封装格式解析
查看>>
最简单的基于FFMPEG的封装格式转换器(无编解码)
查看>>
base64 编码原理
查看>>
单链表是否有环的问题
查看>>
判断两个链表是否相交并找出交点
查看>>