前面两篇Blog简单的介绍了UICollection的基本使用并实现了类似Android的Gallery效果,这篇文章使用UICollection来实现瀑布流效果,代码主要是在极客学院Carol老师的视频,并在提供的demo下直接修改代码,进行屏幕适配,最终效果如下图

(1)ViewController.h文件

@interface ViewController : UIViewController<UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>
@property (nonatomic, strong) UICollectionView *collectionView;@end

ViewController.m文件

#import "ViewController.h"
#import "WaterFallFlowLayout.h"
#import "WaterFallUICollectionViewCell.h"
#define WIDTH ([UIScreen mainScreen].bounds.size.width-20)/3
CGFloat const kImageCount = 16;
static NSString *identifier = @"collectionView";
@interface ViewController ()
@property (nonatomic, strong) NSArray  *imageArr;
@end@implementation ViewController#pragma mark - 图片懒加载
-(NSArray*)imageArr{if (!_imageArr) {NSMutableArray *muArr = [NSMutableArray array];for (int i=1; i<=kImageCount; i++) {UIImage *image = [UIImage imageNamed:[[NSString alloc] initWithFormat:@"image%d",i]];[muArr addObject:image];}_imageArr = muArr;}return _imageArr;
}- (void)viewDidLoad {[super viewDidLoad];WaterFallFlowLayout *flowLayout = [[WaterFallFlowLayout alloc] init];self.collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:flowLayout];self.collectionView.backgroundColor = [UIColor redColor];self.collectionView.delegate = self;self.collectionView.dataSource = self;[self.collectionView registerClass:[WaterFallUICollectionViewCell class] forCellWithReuseIdentifier:identifier];[self.view addSubview:self.collectionView];
}#pragma mark - UICollectionView dataSource
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{return [self.imageArr count];
}-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{WaterFallUICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];cell.image = self.imageArr[indexPath.item];return cell;
}#pragma mark - 计算图片高度
-(float)imageHeight:(float)height width:(float)width{/*高度/宽度 = 压缩后高度/压缩后宽度*/float newHeight = height/width*(WIDTH);return newHeight;
}#pragma mark - cell大小
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{UIImage *imge = [self.imageArr objectAtIndex:indexPath.row];float height = [self imageHeight:imge.size.height width:imge.size.width];return CGSizeMake(WIDTH, height);
}#pragma mark - 边距
-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{UIEdgeInsets edgeInsets = {5,5,5,5};return edgeInsets;
}@end

(2)WaterFallFlowLayout.h文件

#import <UIKit/UIKit.h>@interface WaterFallFlowLayout : UICollectionViewFlowLayout
@property(nonatomic,assign)id<UICollectionViewDelegateFlowLayout> delegate;
@property(nonatomic,assign)NSInteger cellCount;//cell的个数
@property(nonatomic,strong)NSMutableArray *colArr;//存放列的高度
@property(nonatomic,strong)NSMutableDictionary *attributeDict;//cell的位置信息
@end

WaterFallFlowLayout.m文件

#import "WaterFallFlowLayout.h"
CGFloat const colCount = 3;
@implementation WaterFallFlowLayout
//准备布局:得到cell的总个数,为每个cell确定自己的位置
- (void)prepareLayout{[super prepareLayout];NSLog(@"prepareLayout");_colArr = [NSMutableArray array];_attributeDict = [NSMutableDictionary dictionary];self.delegate = (id<UICollectionViewDelegateFlowLayout>)self.collectionView.delegate;//获取cell的总个数_cellCount = [self.collectionView numberOfItemsInSection:0];if (_cellCount == 0) {return;}float top = 0;for (int i = 0; i < colCount; i++) {[_colArr addObject:[NSNumber numberWithFloat:top]];}//循环调用layoutForItemAtIndexPath方法,为每个cell布局,将indexPath传入,作为布局字典的key//layoutAttributesForItemAtIndexPath方法的实现,这里用到了一个布局字典,其实就是将每个cell的位置信息与indexPath相对应,将它们放到字典中,方便后面视图的检索for (int i = 0; i < _cellCount; i++) {[self layoutItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];}}//此方法会多次调用,为每个cell布局
- (void)layoutItemAtIndexPath:(NSIndexPath *)indexPath{//通过协议得到cell的间隙NSLog(@"layoutItemAtIndexPath");UIEdgeInsets edgeInsets = [self.delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:indexPath.row];CGSize itemSize = [self.delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];float col = 0;float shortHeight = [[_colArr objectAtIndex:col] floatValue];//找出高度最小的列,将cell加到最小列中for (int i = 0; i < _colArr.count; i++) {float height = [[_colArr objectAtIndex:i] floatValue];if (height < shortHeight) {shortHeight = height;col = i;}}float top = [[_colArr objectAtIndex:col] floatValue];NSLog(@"top:%f",top);//确定cell的frameCGRect frame = CGRectMake(edgeInsets.left + col * (edgeInsets.left + itemSize.width), top + edgeInsets.top, itemSize.width, itemSize.height);NSLog(@"frme:%f,%f,%f,%f",edgeInsets.left + col * (edgeInsets.left + itemSize.width),top + edgeInsets.top,itemSize.width,itemSize.height);//更新列高[_colArr replaceObjectAtIndex:col withObject:[NSNumber numberWithFloat:top + edgeInsets.top + itemSize.height]];//每个cell的frame对应一个indexPath,放入字典中[_attributeDict setObject:indexPath forKey:NSStringFromCGRect(frame)];
}- (NSArray *)indexPathsOfItem:(CGRect)rect{//遍历布局字典通过CGRectIntersectsRect方法确定每个cell的rect与传入的rect是否有交集,如果结果为true,则此cell应该显示,将布局字典中对应的indexPath加入数组NSLog(@"indexPathsOfItem");NSMutableArray *array = [NSMutableArray array];for (NSString *rectStr in _attributeDict) {CGRect cellRect = CGRectFromString(rectStr);if (CGRectIntersectsRect(cellRect, rect)) {NSIndexPath *indexPath = _attributeDict[rectStr];[array addObject:indexPath];}}return array;
}//返回cell的布局信息,如果忽略传入的rect一次性将所有的cell布局信息返回,图片过多时性能会很差
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{NSLog(@"layoutAttributesForElementsInRect");NSMutableArray *muArr = [NSMutableArray array];//indexPathsOfItem方法,根据传入的frame值计算当前应该显示的cellNSArray *indexPaths = [self indexPathsOfItem:rect];for (NSIndexPath *indexPath in indexPaths) {//  UICollectionViewLayoutAttributes *attribute = [self layoutAttributesForItemAtIndexPath:indexPath];UICollectionViewLayoutAttributes *attribute = [self layoutAttributesForItemAtIndexPath:indexPath];[muArr addObject:attribute];}return muArr;
}//返回每个CollectionViewCell的属性
-(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];for (NSString *rectStr in _attributeDict) {if (_attributeDict[rectStr]==indexPath) {attributes.frame = CGRectFromString(rectStr);}}return attributes;
}//最后还要实现这个方法,返回collectionView内容的大小
//只需要遍历前面创建的存放列高的数组得到列最高的一个作为高度返回就可以了
- (CGSize)collectionViewContentSize{NSLog(@"collectionViewContentSize");CGSize size = self.collectionView.frame.size;float maxHeight = [[_colArr objectAtIndex:0] floatValue];//查找最高的列的高度for (int i = 0; i < _colArr.count; i++) {float colHeight = [[_colArr objectAtIndex:i] floatValue];if (colHeight > maxHeight) {maxHeight = colHeight;}}size.height = maxHeight;return size;
}
@end

(3)WaterFallUICollectionViewCell.h文件

@interface WaterFallUICollectionViewCell : UICollectionViewCell
@property(nonatomic,strong) UIImage *image;
@end

WaterFallUICollectionViewCell.m文件

#import "WaterFallUICollectionViewCell.h"
#define WIDTH ([UIScreen mainScreen].bounds.size.width-20)/3@implementation WaterFallUICollectionViewCell
- (void)setImage:(UIImage *)image{if (_image != image) {_image = image;}[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect{float newHeight = _image.size.height / _image.size.width * WIDTH;[_image drawInRect:CGRectMake(0, 0, WIDTH, newHeight)];self.backgroundColor = [UIColor grayColor];
}@end

(4)运行测试

demo下载地址:http://download.csdn.net/detail/dolacmeng/8682759

iOS UICollectionView实现瀑布流(3)相关推荐

  1. iOS基础UI瀑布流界面简单搭建

    ios UI基础瀑布流 顾名思义是将界面以瀑布流水般的展现出来,使用瀑布流,首先对数据进行懒加载,传入数据后,使用UIcollectionView控件在main.storyboard里进行简单的布局 ...

  2. UICollectionView,CollectionView,瀑布流

    UICollectionView 布局自定义 IOS collectionViewCell防止复用的两种方法 Swift - 实现UICollectionView分组头悬停效果(方法1:使用自定义布局 ...

  3. 利用UICollectionView实现瀑布流

    利用UICollectionView实现瀑布流通过自定义布局来实现. - 自定义类继承UICollectionViewLayout: 必须重写的方法有: //决定每个item的位置: - (nulla ...

  4. iOS开发之瀑布流照片墙实现

    想必大家已经对互联网传统的照片布局方式司空见惯了,这种行列分明的布局虽然对用户来说简洁明了,但是长久的使用难免会产生审美疲劳.现在网上流行一种叫做"瀑布流"的照片布局样式,这种行与 ...

  5. ios UICollectionViewLayout 横向瀑布流

    2019独角兽企业重金招聘Python工程师标准>>> 效果: 截图没有显示出抖动效果 // // mierLayout.m // diaojiba // // Created by ...

  6. iOS开发之窥探UICollectionViewController(四) --一款功能强大的自定义瀑布流

    在上一篇博客中<iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流>,自定义瀑布流的列数,Cell的外边距,C ...

  7. 【无限互联】iOS开发之瀑布流布局实现(UICollectionView拓展Layout)

    移动应用在进行图片或照片浏览是都喜欢才用瀑布流的方式来进行布局,相比于老版的等高等宽的传统照片布局方式,瀑布流显然显得更有吸引力. 其实对于瀑布流的实现原理并不是多难,像常见的应用一般都是把屏幕分为等 ...

  8. IOS开发 多section瀑布流+悬停Header OC

    写在前面的话 问题:在实习期间才开始学习IOS开发,项目中要求实现类似小红书首页效果的瀑布流,包括多种Section,每种Section有对应的头部HeaderView,以及上滑时实现Header悬停 ...

  9. iOS 瀑布流之栅格布局

    代码地址如下: http://www.demodashi.com/demo/14760.html 一 .效果预览 二.确定需求 由下面的需求示意图可知模块的最小单位是正方形,边长是屏幕宽除去边距间隔后 ...

最新文章

  1. Mat,Iplimage,vector,vector_vector_Point2f等类型之间的相互转换
  2. 《赛博朋克2077》是捏脸游戏?上科大学生社团开发了一款赛博“滤镜”
  3. php exec 怎么确定执行成功_php执行系统外部命令的4种方法
  4. SpringMVC以及SSM整合
  5. php1045无法登录mysql_phpstudy安装完成后打开phpmyadmin提示#1045 无法登录 MySQL 服务器...
  6. mac git配置 idea
  7. eclipse如何添加Memory Analyzer
  8. 使用AD14制作PCB的全部流程以及PCB打样流程介绍
  9. 网易云IM(即时通讯) 互动直播集成
  10. Rxjava2.X的一些讲解
  11. php hex2bin_PHP bin2hex()函数与示例
  12. 周受资从小米跳槽字节跳动任CFO、拜腾创始人戴雷将加盟恒大汽车 | 高管变动2021年3月22日-28日...
  13. IMDB 电影评论情感分类数据集
  14. 您的php似乎没有安装运行wordpress所必需的mysql扩展_“您的 PHP 似乎没有安装运行 WordPress 所必需的 MySQL 扩展”处理方法...
  15. 蓝桥杯- 算法训练-Beaver's Calculator
  16. 机器学习篇——MNIST手写数字识别
  17. 卡车智能驾驶进入“后法规”时代
  18. 关于如何在coursera.org上旁听好课
  19. Arrays.aslist新建的list集合不能add()、remove()你知道吗?
  20. Python计算机视觉编程第十章——OpenCV基础知识

热门文章

  1. ssh免密连接远程服务器
  2. 谷歌 notification 测试 页面
  3. dataTable 从服务器获取数据源的两种表现形式
  4. 为什么你的工作经验不值钱
  5. ThinkPHP项目笔记之登录,注册,安全退出篇
  6. 配置 php-fpm 监听的socket
  7. Maven 手动添加第三方依赖包及编译打包和java命令行编译JAVA文件并使用jar命令打包...
  8. oracle 无效索引
  9. cmake语法【一】
  10. linux中iptables入门教程--设置静态防火墙