您的位置:首页 > 其它

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

2016-04-27 16:11 281 查看
一.前期工作

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];

            //设置item的x, 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





好啦,这就是瀑布流的效果,中间没有显示出来的是因为图片的网址失效了.大家有什么不懂的可以评论回复我~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息