iOS collectionView实现瀑布流
#import "WaterFlowLayout.h"#import "ShopModel.h"@interface WaterFlowLayout()// 保存每一列最大的Y值@property (nonatomic,strong)NSMutableArray *maxYArray;@end// 最大列数staticNSInteger maxColumn
1.模型:需要有宽高来控制cell的高度,
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface LYBDiscoveryRecomendcollectionviewmodel : NSObject
@property(nonatomic,assign)NSInteger h;
@property(nonatomic,assign)NSInteger w;
@end
NS_ASSUME_NONNULL_END
#import "LYBDiscoveryRecomendcollectionviewmodel.h"
@implementation LYBDiscoveryRecomendcollectionviewmodel
@end
2.
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface LYBDiscoveryRecomandcollectionview : UIView
@end
NS_ASSUME_NONNULL_END
#import "LYBDiscoveryRecomandcollectionview.h"
#import "LYBDiscoveryRecomandWaterFlowLayout.h"
#import "LYBDiscoveryrecommandcollectionviewcell.h"
#import "LYBDiscoveryRecomendcollectionviewmodel.h"
@interface LYBDiscoveryRecomandcollectionview()<UICollectionViewDelegate,UICollectionViewDataSource,LYBDiscoveryRecomandWaterFlowLayoutdelegate>
@property(nonatomic,strong)NSMutableArray *modelarr;
@end
static 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 <UIKit/UIKit.h>
@class LYBDiscoveryRecomandWaterFlowLayout;
NS_ASSUME_NONNULL_BEGIN
@protocol LYBDiscoveryRecomandWaterFlowLayoutdelegate <NSObject>
-(CGFloat)LYBDiscoveryRecomandWaterFlowLayout:(LYBDiscoveryRecomandWaterFlowLayout*)LYBDiscoveryRecomandWaterFlowLayout withIndexPath:(NSIndexPath *)indexPath andItemWidth:(CGFloat)itemWidth;
@end
@interface LYBDiscoveryRecomandWaterFlowLayout : UICollectionViewFlowLayout
@property(nonatomic,weak)id<LYBDiscoveryRecomandWaterFlowLayoutdelegate>delegate;
@end
NS_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 的 size
CGSize 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 <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 -
#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: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 <maxColumn; i++) {
CGFloat arryY = [self.maxYArray[i]doubleValue];
if (maxY < arryY) {
maxY = arryY;
}
}
}
return CGSizeMake(0, maxY +10);
}
@end
4.
#import <UIKit/UIKit.h>
#import "LYBDiscoveryRecomendcollectionviewmodel.h"
NS_ASSUME_NONNULL_BEGIN
@interface LYBDiscoveryrecommandcollectionviewcell : UICollectionViewCell
@property(nonatomic,strong)LYBDiscoveryRecomendcollectionviewmodel *model;
@end
NS_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
更多推荐

所有评论(0)