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)prepareLayout
2)- (CGSize)collectionViewContentSize
3)- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
4)- (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获取总共有多少个item
NSInteger 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值+下内边距
return
CGSizeMake(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的frame
attributes.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 {
return
self.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];
return
image.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 ...
随机推荐
- windows命令总结
工作中还是经常使用windows系统,将windows中常用的命令进行总结. 1. 从命令行打开资源管理器,即文件夹 start . 2. 查看端口占用情况 比如查看3000端口的占用情况 netst ...
- WIFI万能钥匙协议分析
WIFI万能钥匙协议分析 需求: 上android 市场下载任意一款,wifi万能钥匙 软件,对其进行 协议分析和逆向,达成如下结果:通过对软件的分析,完成自动化爬虫,爬wifi万能钥匙的wifi库, ...
- bzoj 2798 [Poi2012]Bidding 博弈论+dp
题目大意 A和B两个人在玩一个游戏,这个游戏是他们轮流操作一对整数(x,y). 初始时(x,y)=(1,0),可以进行三种操作: 将(x,y)变成(1,x+y). 将(x,y)变成(2x,y). 将( ...
- vue2 父子组件间通信
父组件往子组件传值 props 传text father.vue <template> <div class="father"> {{'我是父组件'}} & ...
- 快充 IC BQ25896 如何判斷 手機插著 adapter 充電器時,adapter Iout 大於限制,adapter Vout 小於 限制,導致 battery 不但沒充電且還需放電。
若電池在 放電時,ICHGR 為0. 若電池在 充電時,ICHGR有變化. 下面有寫到 charge current 所以不是 discharge current 狀況: ...
- wpf GridControl selectAll UnSelect
<Window x:Class="WpfApplication1.GridControlView" xmlns="http://schemas.microsoft. ...
- es6 const let
一.const 1.const 声明的是常量,一旦声明,值将是不可变的: 2.const也具有块级作用域: 3.不能变量提升(必须先声明后使用): 4.const 不可重复声明 5.const 指令指 ...
- ubuntu下打开windows里的txt文件乱码解决
是编码问题引起的问题: Linux下默认的编码是UTF-8,而Windows下默认的编码是GB2312/GBK.执行如下第一条语句即可 gsettings set org.gnome.gedit.pr ...
- Xamarin.Forms XAML控件的公共属性
Xamarin.Forms XAML控件的公共属性 Xamarin.Forms XAML控件有很多.通过官网API,可以查看每个控件的属性.但是官网只给出了控件的特有属性,而公共属性没有列出.所以 ...
- jenkins集群节点构建maven(几乎是坑最多的)
业务量变大时,单台的jenkins进行自动化构建部署,就显得没那么灵活,jenkins的集群并非像web服务器.mysql集群那样,jenkins的集群无需在额外的主机安装jenkins,但是用于ja ...