自定义瀑布流

来源:互联网 发布:浮生一日知乎 编辑:程序博客网 时间:2024/05/09 01:12

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

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
原创粉丝点击