UICollectionView和UITableView类似,它也是datasource和delegate设计模式的:datasource为view提供数据源,告诉view要显示些什么东西,以及如何显示它们,delegate提供一些样式的细节以及用户交互的响应。
UICollectionView 和 UICollectionViewController 类是iOS6 新引进的API,用于展示集合视图,布局更加灵活,可实现多列布局,用法类似于UITableView 和 UITableViewController 类。
使用UICollectionView 必须实现UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout这三个协议。
collectionView和tableView都有cell,只是这里面叫item,我们可以去规定每一个item的位置UICollectionView
1.创建一个ViewController,UIView,UICollectionView
2.在创建的View.h设置UICollectionView的属性,
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self){
[self setupView];
}
return self;
}
- (void)setupView{
self.backgroundColor = [UIColor orangeColor];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
//设置每一个元素的大小
layout.itemSize = CGSizeMake(100, 100);
//设置内边距大小
layout.sectionInset = UIEdgeInsetsMake(20, 20, 40, 20);
//滚动方向
//layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
//设置最小行间距
layout.minimumLineSpacing = 50;
//设置最小列间距
layout.minimumInteritemSpacing = 10;//行间距的设置一定会实现,列间距的设置不一定会实现,因为存在剩余空间的平均分配问题
//行间距因滚动的方向不同,作用的效果方向也不同
self.collcction =[[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:layout];
[self addSubview:self.collcction];
}
/*
layout:布局
UIcollectionViewlayout 是一个基类。是所有的布局文件的父类,但是里面没有元素的位置定义
UICollectionViewLayout 是上面的一个子类,他实现了元素的定义,实现了流水式布局
*/
@end
//3.在CollectionViewCell.h上声明属性,在.m中实现
#import "MyCollectionViewCell.h"
@implementation MyCollectionViewCell
//重写,然后布局
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
[self setupItem];
}
return self;
}
- (void)setupItem{
//1.collectionView里面没有tableView那样的三个基本标签,里面是空的
//2.collectionView也是将所有的控件都放在contentView上面的
//创建一个label,让label的大小和item的大小一样
self.label = [[UILabel alloc] initWithFrame:self.contentView.bounds];
[self.contentView addSubview:self.label];
self.imageView = [[UIImageView alloc] initWithFrame:self.contentView.bounds];
self.imageView.image = [UIImage imageNamed:@"92.jpg"];
[self.contentView addSubview:self.imageView];
}
//当bounds发生改变的时候自动调用这个方法
-(void)layoutSubviews{
//在这里面对imageView的大小进行调整
//1.拿到imageView的大小
CGRect frame1 = self.imageView.frame;
//2.拿到当前item 的大小
CGRect frame2 = self.frame;
//3.修改数据并设置回去
frame1.size = frame2.size;
self.imageView.frame = frame1;
}
@end
//4.在ViewController.m中
#import "RootViewController.h"
#import "MyCollectionViewCell.h"
@interface RootViewController ()<UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout>
@end
@implementation RootViewController
- (void)loadView{
[super loadView];
self.rv = [[RootView alloc] initWithFrame:[[UIScreen mainScreen]bounds]];
self.view = self.rv;
}
- (void)viewDidLoad {
[super viewDidLoad];
collectionView是tableView的升级版,可以理解为多列的tableView
collectionView和tableView都有cell,只是这里面叫item,我们可以去规定每一个item的位置
self.rv.collcction.dataSource = self;
self.rv.collcction.delegate = self;
//注册
[self.rv.collcction registerClass:[MyCollectionViewCell class] forCellWithReuseIdentifier:@"collection_cell"];
}
//
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 100;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.row % 2) {
return CGSizeMake(120, 120);
}else{
return CGSizeMake(80, 80);
}
}
//
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
MyCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"collection_cell" forIndexPath:indexPath];
//设置每个元素的颜色
cell.backgroundColor = [UIColor cyanColor];
cell.label.text = [NSString stringWithFormat:@"第%ld个标签",indexPath.row];
cell.imageView.image = [UIImage imageNamed:@"92.jpg"];
return cell;
}
//瀑布流
效果图:
1.创建ViewController,View,Model类,CollectionViewCell,Layout
2.引入图片网络,大小的文件,还有第三方库SDWeblmage
3.在创建的View中写layout和collection
#import "RootView.h"
@implementation RootView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setupView];
}
return self;
}
- (void)setupView{
self.backgroundColor = [UIColor orangeColor];
//使用瀑布流的专属layout
WaterFlowLayout *layout = [[WaterFlowLayout alloc] init];
//设置属性
self.layout = layout;
//其他属性
CGFloat w = ([UIScreen mainScreen].bounds.size.width - 40) / 3;
//设置item的大小
layout.itemSize = CGSizeMake(w, w);
//设置内边距的大小
layout.sectionInsets = UIEdgeInsetsMake(10, 10, 10, 10);
//item的间距
layout.spacing = 10;
//一共有几列
layout.numberOfColumns = 3;
self.collection = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:layout];
[self addSubview:self.collection];
}
4.在CollectionViewCell中写imageView
#import "MyCollectionViewCell.h"
@implementation MyCollectionViewCell
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
[self setupItem];
}
return self;
}
- (void)setupItem{
self.imageView = [[UIImageView alloc] initWithFrame:self.contentView.bounds];
self.imageView.backgroundColor = [UIColor colorWithRed:arc4random()%256/255.0 green:arc4random()%256/255.0 blue:arc4random()%256/255.0 alpha:1];
self.imageView.image = [UIImage imageNamed:@"92.jpg"];
[self.contentView addSubview:self.imageView];
}
- (void)layoutSubviews{
[super layoutSubviews];
self.contentView.frame = self.bounds;
self.imageView.frame = self.contentView.bounds;
}
5.在layout中设置瀑布流图片的布局
WeterFlowLayout.h
#import <UIKit/UIKit.h>
//设置协议
@protocol WaterFlowLayoutDelegate <NSObject>
- (CGFloat)heightForItemAtIndexPath:(NSIndexPath *)indexPath;
@end
@interface WaterFlowLayout : UICollectionViewLayout
//item的大小,最主要是获取列宽
@property (nonatomic,assign)CGSize itemSize;
//内边距
@property (nonatomic,assign)UIEdgeInsets sectionInsets;
//item的间距
@property (nonatomic,assign)CGFloat spacing;
//一共有几列
@property (nonatomic,assign)NSInteger numberOfColumns;
//代理,用于锁定数据
@property (nonatomic,assign)id<WaterFlowLayoutDelegate>delegatel;
@end
WeterFlowLayout.m
#import "WaterFlowLayout.h"
@interface WaterFlowLayout ()
//保存一共有几个item
@property (nonatomic,assign)NSInteger numberOfItems;
//保存计算好的每一个item的位置信息
@property (nonatomic,strong)NSMutableArray *itemAttributes;
//保存每一列的高度
@property (nonatomic,strong)NSMutableArray *columnsHeights;
//找到当前最长列标号
- (NSInteger)indexForHeightestColumn;
//找到当前最短列标号
- (NSInteger)indexForShortestColumn;
@end
@implementation WaterFlowLayout
//懒加载
- (NSMutableArray *)columnsHeights{
if (_columnsHeights == nil) {
_columnsHeights = [NSMutableArray array];
}
return _columnsHeights;
}
- (NSMutableArray *)itemAttributes{
if (_itemAttributes == nil) {
_itemAttributes = [NSMutableArray array];
}
return _itemAttributes;
}
//找到当前最长列标号
- (NSInteger)indexForHeightestColumn{
NSInteger index = 0;
CGFloat length = 0;//记录最长的长度
for (int i = 0; i < self.numberOfColumns; i++) {
//将数组里面的对象转换成float类型的值
CGFloat currentValue = [self.columnsHeights[i] floatValue];
if (currentValue > length) {
length = currentValue;
index = i;
}
}
return index;
}
//找到当前最短列标号
- (NSInteger)indexForShortestColumn{
NSInteger index = 0;
CGFloat length = MAXFLOAT;//MAXFLOAT:宏定义的最大值
for (int i = 0; i < self.numberOfColumns; i++) {
//拿到挡墙对象的float值
CGFloat currentValue = [self.columnsHeights[i] floatValue];
if (currentValue < length) {
length = currentValue;
index = i;
}
}
return index;
}
//准备布局,在这里计算每一个item的frame
- (void)prepareLayout{
[super prepareLayout];
//拿到有多少个元素
self.numberOfItems = [self.collectionView numberOfItemsInSection:0];
//给每一列添加一个top的高度
for (int i = 0; i < self.numberOfColumns; i++) {
self.columnsHeights[i] = @(self.sectionInsets.top);//NSNumber @()将数字转化为字面量
}
//挨个去给每一个元素创建属性信息,并存放到数组中
for (int i = 0; i < self.numberOfItems; i++) {
//1.确定元素高度最短列
NSInteger shortestIndex = [self indexForShortestColumn];
//2.拿到最短列的高度备用
CGFloat height = [self.columnsHeights[shortestIndex] floatValue];
//3.计算x的值,目标X等于内边距的左边距 + (宽+item间距)*列数
CGFloat detalX = self.sectionInsets.left + (self.itemSize.width + self.spacing) * shortestIndex;
//4.计算Y的值
CGFloat detalY = height + self.spacing;
//创建属性
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
//5.调用代理计算高度
CGFloat itemHeight = 0;
if (_delegatel &&[_delegatel respondsToSelector:@selector(heightForItemAtIndexPath:)]) {
//计算Y的高度
itemHeight = [_delegatel heightForItemAtIndexPath:indexPath];
}
//生成frame
attributes.frame = CGRectMake(detalX, detalY, self.itemSize.width, itemHeight);
//将这个信息对象放到数组里面去
[self.itemAttributes addObject:attributes];
//更新这一列的高度
self.columnsHeights[shortestIndex] = @(detalY + itemHeight);
}
}
//返回contentView的大小
- (CGSize)collectionViewContentSize{
//求最高列的高度
NSInteger longsIndex = [self indexForHeightestColumn];
CGFloat height = [self.columnsHeights[longsIndex]floatValue];
//拿到contentView的原始大小
CGSize size = self.collectionView.frame.size;
size.height = height + self.sectionInsets.bottom;
return size;
}
//返回每一个item的Attribute(属性信息)
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
return self.itemAttributes ;
}
@end
6.在Model.h
#import <Foundation/Foundation.h>
@interface Model : NSObject
@property (nonatomic,copy)NSString *thumbURL;
@property (nonatomic,assign)NSInteger width;
@property (nonatomic,assign)NSInteger height;
@end
Model.m
#import "Model.h"
@implementation Model
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{
NSLog(@"找不到键值对");
}
@end
7.在ViewController中
#import "RootViewController.h"
#import "MyCollectionViewCell.h"
#import "Model.h"
#import "UIImageView+WebCache.h"
@interface RootViewController ()<UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout,WaterFlowLayoutDelegate>
@property (nonatomic,strong)NSMutableArray *data;
@end
@implementation RootViewController
- (void)loadView{
[super loadView];
self.rv = [[RootView alloc] initWithFrame:[[UIScreen mainScreen]bounds]];
self.view = self.rv;
}
- (void)viewDidLoad {
[super viewDidLoad];
//注册
[self.rv.collection registerClass:[MyCollectionViewCell class] forCellWithReuseIdentifier:@"c_cell"];
self.rv.collection.dataSource = self;
self.rv.collection.delegate = self;
[self loadData];
self.rv.layout.delegatel = self;
// Do any additional setup after loading the view.
}
- (CGFloat)heightForItemAtIndexPath:(NSIndexPath *)indexPath{
//拿到model
Model *m = self.data[indexPath.item];
//获取图片宽度
CGFloat w = ([UIScreen mainScreen].bounds.size.width - 40) / 3;
CGFloat h = (w * m.height) / m.width;
return h;
}
- (void)loadData{
NSString *path = [[NSBundle mainBundle] pathForResource:@"Data" ofType:@"json"];
NSData *dataFile = [NSData dataWithContentsOfFile:path];
NSArray *tempArray = nil;
if (nil != dataFile) {
tempArray = [NSJSONSerialization JSONObjectWithData:dataFile options:NSJSONReadingAllowFragments error:nil];
}
self.data = [NSMutableArray array];
for (NSDictionary *dic in tempArray) {
Model *m = [[Model alloc] init];
[m setValuesForKeysWithDictionary:dic];
[self.data addObject:m];
}
}
//有多少个元素
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return self.data.count;
}
//
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
MyCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"c_cell" forIndexPath:indexPath];
cell.imageView.image = [UIImage imageNamed:@"92.jpg"];
cell.backgroundColor = [UIColor colorWithRed:arc4random()%256/255.0 green:arc4random()%256/255.0 blue:arc4random()%256/255.0 alpha:1];
Model *model = self.data[indexPath.row];
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:model.thumbURL]];
return cell;
}