iOS开发 UI UICollectionView 瀑布流

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



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值