自定义CollectionViewCell之-----瀑布流效果

一.前期工作

1.定义一个自定义CollectionViewCell,继承于UICollectionViewCell,定义imageView属性,在.m文件里重写dealloc,并且重写initWithFrame方法(viewController中创建自定义collectionCell时会用到这个方法)

#import "myCollectionViewCell.h"


@implementation myCollectionViewCell

- (void)dealloc {

    [_imageV release];

    [super dealloc];

}


- (instancetype)initWithFrame:(CGRect)frame {

    self = [super initWithFrame:frame];

    if (self) {

        self.imageV = [[UIImageView alloc] initWithFrame:self.contentView.bounds];

        [self.contentView addSubview:self.imageV];

        [self.imageV release];

    }

    return self;

}

@end



2.定义model类,传值和赋值的过程,类的属性包括图片的网址,图片的width,height(要记住里面使用KVC赋值,重写initWithDic方法, 并重写KVC的两个方法,防止崩溃)

.h

#import <Foundation/Foundation.h>


@interface model : NSObject

@property(nonatomic, copy)NSString *thumbURL;

@property(nonatomic, retain)NSNumber *width;

@property(nonatomic, retain)NSNumber *height;


- (instancetype)initWithDic:(NSDictionary *)deic;

@end


.m

#import "model.h"


@implementation model

- (void)dealloc{

    [_thumbURL release];

    [_width release];

    [_height release];

    [super dealloc];

}


//使用 kvc 赋值

- (instancetype)initWithDic:(NSDictionary *)dic{

    self = [super init];

    if (self) {

        [self setValuesForKeysWithDictionary:dic];

    }

    return self;

}

//重写防止崩溃的方法

//当对象的属性类型是非对象类型而且赋值时为 nil ,会崩溃的情况.

- (void)setNilValueForKey:(NSString *)key{

    

}

//解决当没有对应的 key ,会崩溃的情况

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

    

}

@end


2.在viewController中做基本工作(1.解析文件,在这里我传入的是json

文件2.设定UICollectionView并遵循协议,写重用方法,设定分区数,设定item个数
)

在这里就不放出代码段了,会在最后直接给出全部的viewController中的代码


二.开始最重要的自定义布局,我们知道collectionCell在布局中 需要一个继承于UICollectionViewLayout类的布局类对象flowLayout.所以我们想要自定义布局,就要自定义一个类,继承于UICollectionViewLayout,然后再其中写自定义的布局代码.

在自定义UICollectionViewLayout类中,定义属性(这些属性在系统的layout中是有的,因为现在是自定义,所以要自己写出来),然后写出一系列方法,下面是myLayout中的代码

myLayout.h

#import <UIKit/UIKit.h>


@protocol myLayoutDelegate <NSObject>

//给位置,返回对应的item高度

- (CGFloat) collectionView:(UICollectionView *)collectionView heightForItemAtIndexPath:(NSIndexPath *)indexPath;


@end


@interface myLayout : UICollectionViewLayout

//设置属性(这些属性在系统的layout中是有的,因为现在是自定义,所以要自己写出来)

@property(nonatomic) CGFloat itemWidth;//item的宽

@property(nonatomic) CGFloat minLineSpace;//最小行间距

@property(nonatomic) CGFloat itemSpace;//item之间的间距

@property(nonatomic) UIEdgeInsets sectionInsets;//分区缩进

@property(nonatomic) NSUInteger numberOfColumns;//列数

@property(nonatomic) NSUInteger numberOfitems;//item的个数


//设置代理属性

@property(nonatomic, assign)id <myLayoutDelegate>delegate;

@end


myLayout.m.

#import "myLayout.h"

#define kScreenWIDTH [UIScreen mainScreen].bounds.size.width

@interface myLayout()

@property(nonatomic, retain)NSMutableArray *columnsHeightArr;//用来存放每一列当前的高

@property(nonatomic, retain)NSMutableArray *attributeArr;//用来存放每一个布局属性对象

@end


@implementation myLayout

//重写dealloc

- (void)dealloc {

    [_columnsHeightArr release];

    [_attributeArr release];

    [super dealloc];

}


//两个属性数组的懒加载

- (NSMutableArray *)columnsHeightArr {

    if (!_columnsHeightArr) {

        self.columnsHeightArr = [NSMutableArray arrayWithCapacity:1];

    }

    return [[_columnsHeightArr retain] autorelease];

}

- (NSMutableArray *)attributeArr {

    if (!_attributeArr) {

        self.attributeArr = [NSMutableArray arrayWithCapacity:1];

    }

    return [[_attributeArr retain] autorelease];

}

//重写init方法

- (instancetype)init {

    self = [super init];

    if (self) {

        //设置默认的布局

        self.itemWidth = 110;

        self.sectionInsets = UIEdgeInsetsMake(10, 10, 10, 10);

        self.minLineSpace = 5;

        self.numberOfColumns = 3;

        self.itemSpace = (kScreenWIDTH - self.numberOfColumns * self.itemWidth - self.sectionInsets.left - self.sectionInsets.right) / 2.0;

    }

    return self;

}

//重写准备布局的方法,在该方法内布局

- (void)prepareLayout {

    [super prepareLayout];

    //写我们自己的布局代码

    [self mylayout];

}

- (void)mylayout {

    //获取item个数

    self.numberOfitems = [self.collectionView numberOfItemsInSection:0];

    //初始化每一列的高度,放在columnsHeightArr这个数组中

    for (int i = 0; i < self.numberOfColumns; i++) {

        [self.columnsHeightArr addObject:@(self.sectionInsets.top)];

    }

    //根据有多少个items,不断获取每一个item的高,并计算每个item所在的位置的frame(x, y, w, h).并将所有的位置信息放进属性数组里

    for (int i = 0; i < self.numberOfitems; i++) {

        if ([self.delegate respondsToSelector:@selector(collectionView:heightForItemAtIndexPath:)]) {

           //获取到每一个item对应的高

            CGFloat newHeight = [self.delegate collectionView:self.collectionView heightForItemAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];

            //确定需要将本次获取的高放到哪一列

            NSInteger shortIndex = [self shortestIndex];

            //设置itemx, y

            CGFloat x = self.sectionInsets.left + shortIndex * (self.itemWidth + self.itemSpace);

            CGFloat y = [self.columnsHeightArr[shortIndex]floatValue] + self.minLineSpace;

            //创建布局

            UICollectionViewLayoutAttributes *attrubutes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];

            //设置frame

            attrubutes.frame = CGRectMake(x, y, self.itemWidth, newHeight);

            //把每次建好的属性对象放进数组

            [self.attributeArr addObject:attrubutes];

            //更新高度

            self.columnsHeightArr[shortIndex] = @(y + newHeight + self.minLineSpace);

        }

    }

}

//设置应该显示的最大区域

- (CGSize)collectionViewContentSize {

    //获取当前的内容区域

    CGSize contentSize = self.collectionView.contentSize;

    //获取最长列的坐标

    NSInteger longIndex = [self longestIndex];

    //更新内容区域的height

    contentSize.height = [self.columnsHeightArr[longIndex] floatValue] + self.sectionInsets.bottom;

    return contentSize;

}

//返回需要布局的属性对象

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

    return self.attributeArr[indexPath.row];

}

//返回存储布局属性的数组

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

    return self.attributeArr;

}


//获取最短列的方法

- (NSInteger)shortestIndex {

    NSInteger index = 0;

    CGFloat temp = CGFLOAT_MAX;

    for (id obj in self.columnsHeightArr) {

        if ([obj floatValue] < temp) {

            temp = [obj floatValue];

            index = [self.columnsHeightArr indexOfObject:obj];

        }

    }

    return index;

}

//获取最长列的方法

- (NSInteger)longestIndex {

    NSInteger index = 0;

    CGFloat temp = CGFLOAT_MIN;

    for (id obj in self.columnsHeightArr) {

        if ([obj floatValue] > temp) {

            temp = [obj floatValue];

            index = [self.columnsHeightArr indexOfObject:obj];

        }

    }

    return index;

}



@end


三.ok,最后一步,我们只需要在 ViewController的.m文件里,遵循协议,创建myLayout对象,实现布局传值就OK了.

#import "ViewController.h"

#import "myCollectionViewCell.h"

#import "model.h"

#import "myLayout.h"

#import "UIImageView+WebCache.h"


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

@property(nonatomic, retain)NSMutableArray *datasource;

@end


@implementation ViewController

- (void)dealloc {

    [_datasource release];

    [super dealloc];

}


- (NSMutableArray *)datasource {

    if (!_datasource) {

        self.datasource = [NSMutableArray arrayWithCapacity:1];

    }

    return [[_datasource retain] autorelease];

}


- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

    //1.

    myLayout *flowLayout = [[myLayout alloc] init];

    //2.

    flowLayout.delegate = self;

    

    

    /

    UICollectionView *collecttionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:flowLayout];

    

    collecttionView.dataSource = self;

    collecttionView.delegate = self;

    collecttionView.backgroundColor = [UIColor colorWithWhite:0.298 alpha:1.000];

    [self.view addSubview:collecttionView];

    [collecttionView release];

    [flowLayout release];

    //注册

    [collecttionView registerClass:[myCollectionViewCell class] forCellWithReuseIdentifier:@"item"];

    

    //解析jeon文件

    NSString *path = [[NSBundle mainBundle] pathForResource:@"Data" ofType:@"json"];

    NSData *data = [NSData dataWithContentsOfFile:path];

    NSError *error = nil;

    NSArray *arr = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];

    

    for (NSDictionary *dic in arr) {

        model *m = [[model alloc] initWithDic:dic];

        [self.datasource addObject:m];

        [m release];

    }

}

#pragma mark - myLayoutDelegate

//给位置,返回对应的item高度

- (CGFloat) collectionView:(UICollectionView *)collectionView heightForItemAtIndexPath:(NSIndexPath *)indexPath{

    model *m = self.datasource[indexPath.row];

    CGFloat height = [m.height floatValue];

    CGFloat newheight = 110 / [m.width floatValue] * height;

    

    return newheight;

}



#pragma mark - UICollectionViewDataSource

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

    return self.datasource.count;

}


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

    return 1;

}


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

    myCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"item" forIndexPath:indexPath];

    

    model *m = self.datasource[indexPath.row];

    [cell.imageV sd_setImageWithURL:[NSURL URLWithString:m.thumbURL]];

    return cell;

}













- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}


@end



好啦,这就是瀑布流的效果,中间没有显示出来的是因为图片的网址失效了.大家有什么不懂的可以评论回复我~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值