您的位置:首页 > 产品设计 > UI/UE

iOS开发 UI UICollectionView 瀑布流

2016-01-08 15:37 441 查看
UICollectionView在2012年被提出,已经不是什么新技术了,在此只是做一下简单的实现。集合视图:UICollectionView

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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: