自定义瀑布流

不规则的图片排列起来,改数据直接用就可以

ZCGFlowLayout.h

#import <UIKit/UIKit.h>

@class ZCGFlowLayout;

@protocol ZCGFlowLayoutDelegate <NSObject>

-(CGFloat)ZCGFlowLayout:(ZCGFlowLayout *)flowLayout heightForRowAtIndexPath:(NSIndexPath *)indexPath width:(CGFloat)width;

@end


@interface ZCGFlowLayout : UICollectionViewLayout

//需要设置一下有多少列
//最好不要超过3列
@property(nonatomic,assign)NSInteger columnCounts;

//设置距离屏幕四周的边界距离
@property(nonatomic,assign)UIEdgeInsets edgeInsets;

//行间距
@property(nonatomic,assign)NSInteger rowSpace;

//列间距
@property(nonatomic,assign)NSInteger columnSpace;

//定义一个代理人属性
@property(nonatomic,assign)id<ZCGFlowLayoutDelegate>delegate;


@end

ZCGFlowLayout.m

#import "ZCGFlowLayout.h"

@interface ZCGFlowLayout ()

//用来记录当前每列的高度
@property(nonatomic,retain)NSMutableDictionary *columnDic;

//用来装所有的attributes
@property(nonatomic,retain)NSMutableArray *attributesArr;

@end

@implementation ZCGFlowLayout

//自定义瀑布流的核心在于找出每列里最短的,然后需要用一个字典来存储当前列的长度,然后通过遍历找到当前最短的那列

#pragma mark 第一个方法,先重写初始化方法,完成容器初始化
-(instancetype)init{
    self=[super init];
    if (self) {
        //先初始化用来存高的字典
        self.columnDic=[NSMutableDictionary dictionary];
        self.attributesArr=[NSMutableArray array];
    }
    return self;

}

#pragma mark --瀑布流第二个方法
//重写系统的prepareLayout方法,这个方法当collectionView布局item的时候,该方法会被执行
-(void)prepareLayout{

    [super prepareLayout];

    //根据设置的边框尺寸,先给每列都设置起始的y,就是边框距离屏幕上方的尺寸
    for (NSInteger i = 0; i < self.columnCounts ; i++) {
        NSString *key=[NSString stringWithFormat:@"%ld",i];
        self.columnDic[key]=@(self.edgeInsets.top);
    }

    //获取collectionView上有多少个item
    NSInteger count = [self.collectionView numberOfItemsInSection:0];

    //循环遍历所有item的尺寸
    for (NSInteger i = 0; i < count; i++) {
        [self setItemFrame:i];
    }

}

#pragma mark 第三个方法,用来设置每一个item的尺寸
-(void)setItemFrame:(NSInteger)index{

    //1.首先要获取当前最短的一列
    //2.然后设置item的尺寸

    //定义一个字符串,用来保存最小的列的下标
    __block NSString *minCilumn=@"0";

    //这个方法就是用来遍历字典里所有的key和value的
    [self.columnDic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {

        if([obj floatValue] < [self.columnDic[minCilumn] floatValue]){
            minCilumn=key;
        }

    }];
    //遍历完之后,就可以找到当前最短的那一列

    //计算item的宽
    //宽 = (375 - 左边界 - 右边界 - 列间距 * (列数-1))/列数
    CGFloat width= (375 - self.edgeInsets.left - self.edgeInsets.right - (self.columnCounts - 1) * self.columnSpace) / self.columnCounts;

    //计算item所摆放的x轴坐标
    //x = 左边界 + 当前最短列的下标 * (列间距 + item宽)
    CGFloat x = self.edgeInsets.left + (self.columnSpace + width) * [minCilumn floatValue];

    //指定当前的item是第几分区,第几个
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];

    //高度
    //通过协议方法,把当前第几个item传回去,调用完就能返回一个已经计算好的高
    CGFloat height = [self.delegate ZCGFlowLayout:self heightForRowAtIndexPath:indexPath width:width];

    //找到当前最短列的列高
    CGFloat y = [self.columnDic[minCilumn]floatValue];
    //需要更新一下最下列的列高 = 原有列高 + 高 + 行间距
    self.columnDic[minCilumn] = @(y + height +self.rowSpace);

    //这个类是设置item的frame,透明等属性的,决定了item的属性的信息
    UICollectionViewLayoutAttributes *attributes=[UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    //通过attributes设置item的尺寸
    attributes.frame=CGRectMake(x, y, width, height);

    [self.attributesArr addObject:attributes];
}

#pragma mark -- 第四个方法:用来告诉layout,布局的时候item的信息
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{

    return self.attributesArr;

}

#pragma mark -- 第五个方法:重新设置滚动的范围
-(CGSize)collectionViewContentSize{
    //通过字典找到当前列里最长的列
    __block NSString *maxKey = @"0";
    [self.columnDic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        if ([obj floatValue] > [self.columnDic[maxKey] floatValue]) {
            maxKey=key;
        }
    }];

    //找到最长的列之后,别忘了在最下面,加上底部边界
    CGFloat h = [self.columnDic[maxKey] floatValue]+self.edgeInsets.bottom;
    return CGSizeMake(0, h);

}


@end

MyCollectionViewCell.h

#import <UIKit/UIKit.h>

@interface MyCollectionViewCell : UICollectionViewCell

@property(nonatomic,retain)UIImageView *picImageView;


@end

MyCollectionViewCell.m

#import "MyCollectionViewCell.h"

@implementation MyCollectionViewCell

-(instancetype)initWithFrame:(CGRect)frame{

    self=[super initWithFrame:frame];
    if (self) {
        [self createView];
    }
    return self;
}

-(void)createView{

    self.picImageView=[[UIImageView alloc] initWithFrame:self.contentView.frame];
    [self.contentView addSubview:self.picImageView];
}

//防止重用之后还是上一次出现的尺寸,所以为了能显示新的尺寸,需要重新布局
-(void)layoutSubviews{

    [super layoutSubviews];
    //重新布局cell上的子视图
    self.picImageView.frame=self.contentView.frame;
}

@end

Picture.h

#import <Foundation/Foundation.h>

@interface Picture : NSObject

@property(nonatomic,copy)NSString *thumbURL;
@property(nonatomic,retain)NSNumber *width;
@property(nonatomic,retain)NSNumber *height;

@end

Picture.m

#import "Picture.h"

@implementation Picture

-(void)setValue:(id)value forUndefinedKey:(NSString *)key{

}


@end

ViewController.m

//
//  ViewController.m
//  UI21_自定义瀑布流
//
//  Created by dllo on 16/1/6.
//  Copyright © 2016年 dllo. All rights reserved.
//

#import "ViewController.h"
#import "Picture.h"
#import "ZCGFlowLayout.h"
#import "UIImageView+WebCache.h"
#import "MyCollectionViewCell.h"

@interface ViewController ()<ZCGFlowLayoutDelegate,UICollectionViewDataSource,UICollectionViewDelegate>

@property(nonatomic,retain)NSMutableArray *picArr;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    [self createData];
    [self createView];

}

-(void)createView{

    //创建自定义的layout
    ZCGFlowLayout *flowLayout=[[ZCGFlowLayout alloc] init];
    //设置四周的边框尺寸
    flowLayout.edgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
    //设置列数
    flowLayout.columnCounts= 3;
    //设置行间距
    flowLayout.rowSpace=10;
    //设置列间距
    flowLayout.columnSpace=10;
    //设置代理人
    flowLayout.delegate=self;

    UICollectionView *collectionView=[[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:flowLayout];
    collectionView.delegate=self;
    collectionView.dataSource=self;
    [self.view addSubview:collectionView];
    //cell注册
    [collectionView registerClass:[MyCollectionViewCell class] forCellWithReuseIdentifier:@"reuse"];
}

//用来计算item高的协议方法
-(CGFloat)ZCGFlowLayout:(ZCGFlowLayout *)flowLayout heightForRowAtIndexPath:(NSIndexPath *)indexPath width:(CGFloat)width{

    //图片的原始尺寸都保存在model里
    //计算item的高 = 原始的height * width / 原始的width
    Picture *pic = self.picArr[indexPath.row];
    CGFloat height = [pic.height floatValue] * width / [pic.width floatValue];
    return height;
}

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

    return self.picArr.count;
}

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

    MyCollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"reuse" forIndexPath:indexPath];
    Picture *pic=self.picArr[indexPath.row];
    [cell.picImageView sd_setImageWithURL:[NSURL URLWithString:pic.thumbURL]placeholderImage:[UIImage imageNamed:@"c4.jpg"]];
    return cell;

}

-(void)createData{

    NSString *filePath=[[NSBundle mainBundle] pathForResource:@"Data(1)" ofType:@"json"];
    NSData *data=[NSData dataWithContentsOfFile:filePath];
    NSMutableArray *arr=[NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    self.picArr=[NSMutableArray array];
    for (NSDictionary *dic in arr) {
        Picture *pic=[[Picture alloc] init];
        [pic setValuesForKeysWithDictionary:dic];
        [self.picArr addObject:pic];
    }

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值