iOS之简单瀑布流的实现
iOS之简单瀑布流的实现
前言
超简单的瀑布流实现,这里说一下笔者的思路,详细代码在这里。
实现思路
collectionView能实现各中吊炸天的布局,其精髓就在于UICollectionViewLayout,因此我们要自定义一个layout来继承系统的UICollectionViewLayout,所有工作都在这个类中进行。
1.定义所需属性
瀑布流的思路就是,从上往下,那一列最短,就把下一个item放在哪一列,因此我们需要定义一个字典来记录每一列的最大y值
每一个item都有一个attributes,因此定义一个数组来保存每一个item的attributes。
我们还必须知道有多少列以及列间距、行间距、section到collectionView的边距。
//总列数@property (nonatomic, assign) NSInteger columnCount;//列间距@property (nonatomic, assign) NSInteger columnSpacing;//行间距@property (nonatomic, assign) NSInteger rowSpacing;//section到collectionView的边距@property (nonatomic, assign) UIEdgeInsets sectionInset;//保存每一列最大y值的数组@property (nonatomic, strong) NSMutableDictionary *maxYDic;//保存每一个item的attributes的数组@property (nonatomic, strong) NSMutableArray *attributesArray;
2.重写系统方法
我们一共需要重写4个方法
1)- (void)prepareLayout2)- (CGSize)collectionViewContentSize3)- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath4)- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
- (void)prepareLayout 方法
布局前的一些准备工作都在这里进行,初始化字典,有几列就有几个键值对,key为第几列,value为列的最大y值,初始值为上内边距:
for(int i = 0; i < self.columnCount; i++) {self.maxYDic[@(i)] = @(self.sectionInset.top);}
创建每个item的attributes,并存入数组:
//根据collectionView获取总共有多少个itemNSInteger itemCount = [self.collectionView numberOfItemsInSection:0];//为每一个item创建一个attributes并存入数组for(int i = 0; i < itemCount; i++) {UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];[self.attributesArray addObject:attributes];}
- (CGSize)collectionViewContentSize 方法
用来计算collectionView的contentSize
一般瀑布流只能垂直滚动,不能水平滚动,因此contentSize.width = 0,我们只需要计算contentSize.height即可
从字典中找出最长列的最大y值,再加上下面的内边距,即为contentSize.height
- (CGSize)collectionViewContentSize {//假设第0列是最长的那列__block NSNumber *maxIndex = @0;//遍历字典,找出最长的那一列[self.maxYDic enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSNumber *obj, BOOL *stop) {//如果maxColumn列的最大y值小于obj,则让maxColumn等于obj所属的列if([self.maxYDic[maxIndex] floatValue] < obj.floatValue) {maxIndex = key;}}];//collectionView的contentSize.height就等于最长列的最大y值+下内边距returnCGSizeMake(0, [self.maxYDic[maxIndex] floatValue] + self.sectionInset.bottom);}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath 方法
该方法则用来设置每个item的attributes,在这里,我们只需要简单的设置每个item的attributes.frame即可
首先我们必须得知collectionView的尺寸,然后我们根据collectionView的宽度,以及列数、各个间距来计算每个item的宽度
item的宽度 = (collectionView的宽度 - 内边距及列边距) / 列数
CGFloat collectionViewWidth = self.collectionView.frame.size.width;//self.sectionInset.left:左边距 self.sectionInset.right:右边距//(self.columnCount - 1) * columnSpacing:一行中所有的列边距CGFloat itemWidth = (collectionViewWidth - self.sectionInset.left - self.sectionInset.right - (self.columnCount - 1) * self.columnSpacing) / self.columnCount;
接下来计算item的坐标,要想计算坐标,那就必须知道最短的那一列,先遍历字典,找出最短列是哪一列(minColumn)以及其最大y值。
item的y值就等于最短列的最大y值再加上行间距,x值就等于左边距 + (item宽度 + 列间距) * minColumn
//找出最短的那一列__block NSNumber *minIndex = @0;[self.maxYDic enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSNumber *obj, BOOL *stop) {if([self.maxYDic[minIndex] floatValue] > obj.floatValue) {minIndex = key;}}];//根据最短列的列数计算item的x值CGFloat itemX = self.sectionInset.left + (self.columnSpacing + itemWidth) * minIndex.integerValue;//item的y值 = 最短列的最大y值 + 行间距CGFloat itemY = [self.maxYDic[minIndex] floatValue] + self.rowSpacing;
接下来便是item的高度,我们应该根据图片的原始尺寸以及计算出来的宽度,等比例缩放来计算高度,但是在layout类中,我们是拿不到图片的,因此我们可以定义一个block属性,或者代理,让外界来计算并返回给我们,我们需要将item的宽度以及indexPath传递给外界:
@property (nonatomic, strong) CGFloat(^itemHeightBlock)(CGFloat itemHeight,NSIndexPath *indexPath);
根据返回值来设置item的高度:
if(self.itemHeightBlock) itemHeight = self.itemHeightBlock(itemWidth, indexPath);
最后设置attributes的frame并更新字典:
//设置attributes的frameattributes.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight);//更新字典中的最短列的最大y值self.maxYDic[minIndex] = @(CGRectGetMaxY(attributes.frame));
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 方法
该方法用来返回rect范围内,item的attributes
直接返回attributesArray即可
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {returnself.attributesArray;}
使用
布局类写完了,接下来就可以直接使用了
//创建布局对象XRWaterfallLayout *waterfall = [[XRWaterfallLayout alloc] init];//设置相关属性waterfall.columnCount = 3;//共多少列waterfall.columnSpacing = 10;//列间距waterfall.rowSpacing = 10;//行间距waterfall.sectionInset = UIEdgeInsetsMake(10, 10 , 10, 10);//内边距[waterfall setItemHeightBlock:^CGFloat(CGFloat itemWidth, NSIndexPath *indexPath) {//根据图片的原始尺寸,及显示宽度,等比例缩放来计算显示高度XRImage *image = self.images[indexPath.item];returnimage.imageH / image.imageW * itemWidth;}];collectionView.collectionViewLayout = waterfall;............
具体代码请到这里下载:https://github.com/codingZero/XRWaterfallLayout,觉得不错的,请献上你的star
iOS之简单瀑布流的实现的更多相关文章
- WPF下制作的简单瀑布流效果
最近又在搞点小东西,美化界面的时候发现瀑布流效果比较不错.顺便就搬到了WPF,下面是界面 我对WEB前端不熟,JS和CSS怎么实现的,我没去研究过,这里就说下WPF的实现思路,相当简单. 1.最重要的 ...
- IOS开发之瀑布流照片墙实现
想必大家已经对互联网传统的照片布局方式司空见惯了,这种行列分明的布局虽然对用户来说简洁明了,但是长久的使用难免会产生审美疲劳.现在网上流行一种叫做“瀑布流”的照片布局样式,这种行与列参差不齐的状态着实 ...
- jquery实现简单瀑布流
瀑布流这个概念一直不是很理解,看到别人可以实现,自己弄了很久还是不能实现就很纠结.瀑布流这根刺就一直扎在我心里,一次偶然的机会看到别人实现了瀑布流,我想我是不是也应该再继续把这个未完成的任务画一个圆满 ...
- Jquery简单瀑布流代码示例
最近很多网站都采用瀑布流风格设计,感觉挺有个性的,比较合适做图片类型的网站,没事仿开心网做一个瀑布流示例. 需要用到Jquery,jquery.masonry.min.js <!DOCTYPE ...
- jquery实现简单瀑布流代码
测试环境:ie8 ff13.0.1 chrome22 可以将分页获取的内容依次填入四个div中,瀑布流的分页可以以多页(比如5页)为单位二次分页,这样可以减少后台算法的复杂度 <!DOCTYP ...
- javascript-实现简单瀑布流
直接上代码: <style> *{ margin:0; padding:0; } .waterfall_item{ border:solid 3px #ccc; box-shadow:1p ...
- iOS UITabView简写瀑布流
代码demo 一.tabViewCell,通过image的比例高算出cell 的高度 #import "TableViewCell.h" @implementation Table ...
- iOS开发-UICollectionView实现瀑布流
关于瀑布流的实现网上有很多种解法,自定义控件,TableView+ScrollView,UICollectionView是iOS6发布之后用于展示集合视图,算起来已经发布三年左右了,不过知识点是不变的 ...
- iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流
上篇博客的实例是自带的UICollectionViewDelegateFlowLayout布局基础上来做的Demo, 详情请看<iOS开发之窥探UICollectionViewControlle ...
随机推荐
- 【前端学习笔记】2015-09-06 ~~~~ setAttribute()、slice()
所遇记录: 1.setAttribute("属性",value),相同的还有addAttribute("属性名",value),getAttribute(“属性 ...
- FNV与FNV-1a Hash算法说明【转】
转自:http://blog.csdn.net/jiayanhui2877/article/details/12090575 The core of the FNV hash The core of ...
- x86 下的 struct 變數 member 擺放位置
2 int main() 3 { 4 struct _test { 5 int a; 6 int b; 7 int c; 8 }; 9 10 struct _test test; 11 test.a ...
- Linux 之 Xunsearch(2)
Linux 之 Xunsearch(2) 参考教程:[千峰教育] Xunsearch的项目配置文件: 基本说明: (1)项目配置是一个项目的核心灵魂,非常重要,通常保存为.ini文件, 通常存储在/u ...
- AC日记——魔术球问题 洛谷 P2765
题目描述 «问题描述: 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何2个相邻球的编号之和为完全 ...
- zookeeper源码 — 四、session建立
目录 session建立的主要过程 客户端发起连接 服务端创建session session建立的主要过程 用一张图来说明session建立过程中client和server的交互 主要流程 服务端启动 ...
- CentOS6.7源码安装MySQL5.6
1.源码安装MySQL5.6 # CentOS6操作系统安装完成后,默认会在/etc目录下存在一个my.cnf, # 强制卸载了mysql-libs之后,my.cnf就会消失 rpm -qa | gr ...
- poj 2104 K-th Number(主席树
Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 59058 Accepted: 20529 Case Time Limi ...
- hdu6217(数学)
题意: 你需要输出在16进制下,π的第n位的数字 分析: 既然要求第n位的数字,我们不妨把原来的数字乘上$16^{n-1}$,我们要求的就是这个和式的小数部分的最高位 我们可以用double暴力求出小 ...
- 第2章 Spring Boot 文档
Spring Boot 文档 本节简要介绍了Spring Boot文档,是整个文档的参考指南. 您可以完整阅读本参考指南,或者如果您不感兴趣的话可以跳过该部分. 1. 关于文档 Spring Boot ...