本文共 13145 字,大约阅读时间需要 43 分钟。
1.模型:需要有宽高来控制cell的高度,
#importNS_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.
#importNS_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/