如图所示,通过实现不规则的网格分布,来显示出不同的效果。因为集合视图必须要指定布局还可以显示,所以自定义布局就可以实现瀑布流的效果。

//创建布局对象
WaterFlowLayout *flowLayout = [[WaterFlowLayout alloc] init]; flowLayout.delegate = self;
flowLayout.numberOfColumn = ; //创建集合视图
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:flowLayout];

因为系统自带的布局有四个方法,分别实现了item大小,分区间隔,最小行间距,item之间的间隙大小

@protocol UICollectionViewDelegateFlowLayout <UICollectionViewDelegate>
@optional
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;

所以,自定义FlowLayout,并定义协议,以便定义这些方法。

@protocol WaterFlowLayoutDelegate <NSObject>

//关键方法,此方法的作用是返回每一个item的size大小
//数据中原始图片大小
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
//分区间隔
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
//得到 item之间的间隙大小
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;
//最小行间距
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section; @end @interface WaterFlowLayout : UICollectionViewLayout //瀑布流一共多少列
@property (nonatomic, assign) NSUInteger numberOfColumn; @property (nonatomic, assign) id<WaterFlowLayoutDelegate>delegate;

看图可知,最小高的的item,将作为下一列item的起点。

@interface WaterFlowLayout ()

//存放每一列的高度
@property (nonatomic, retain) NSMutableArray *columnHeightsArray; //存放 每一个item的 属性 包含 frame以及下标
@property (nonatomic, retain) NSMutableArray *attributesArray; @end @implementation WaterFlowLayout //获取最小高度的方法
- (CGFloat)minHeight
{
CGFloat min = ;
for (NSNumber *height in _columnHeightsArray) {
CGFloat h = [height floatValue];
if (min > h) {
min = h;
}
}
return min;
} //获取最大值
- (CGFloat)maxHeight
{
CGFloat max = ;
for (NSNumber *height in _columnHeightsArray) {
CGFloat h = [height floatValue];
if (max < h) {
max = h;
}
}
return max;
} //找到最小高的下标
- (NSUInteger)indexOfMinHeight
{
NSUInteger index = ;
for (int i = ; i < [_columnHeightsArray count]; i ++) {
CGFloat height = [_columnHeightsArray[i] floatValue];
if (height == [self minHeight]) {
index = i;
return index;
}
}
return index;
} //重写父类的布局方法
- (void)prepareLayout
{
[super prepareLayout]; _attributesArray = [[NSMutableArray alloc] init]; _columnHeightsArray = [[NSMutableArray alloc] initWithCapacity:self.numberOfColumn]; //给列高数组里面的对象赋初值
for (int i = ; i < self.numberOfColumn; i ++) {
[_columnHeightsArray addObject:@0.0];
} CGFloat totalWidth = self.collectionView.frame.size.width; //创建 每个item frame中的x、y
CGFloat x = ;
CGFloat y = ; NSUInteger itemCount = [self.collectionView numberOfItemsInSection:]; for (int i = ; i < itemCount; i ++) {
//得到集合视图中 列间隙的个数
NSUInteger numberOfSpace = self.numberOfColumn - ; //代理对象执行代理方法,得到 item之间的间隙大小
CGFloat spaceWidth = [_delegate collectionView:self.collectionView layout:self minimumInteritemSpacingForSectionAtIndex:]; //求每列的宽度,也就是每个item的width
CGFloat width = (totalWidth - spaceWidth * numberOfSpace) / self.numberOfColumn; //获取每一个itemSize的大小
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:]; //数据中原始图片大小
CGSize imageSize = [_delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath]; //通过 约分公式得到固定宽之后的高度是多少
CGFloat height = width * imageSize.height / imageSize.width; UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; //记录每一个item的大小和位置
attribute.frame = CGRectMake(x, y, width, height); //数组保存每个item的位置信息
[_attributesArray addObject:attribute]; NSLog(@"item = %d",i);
NSLog(@"x = %.2f y = %.2f width = %.2f height = %.2f",x,y,width,height); //求列高最小的那一列的下标
NSUInteger minHeightIndex = [self indexOfMinHeight]; //求出最小列的高度
CGFloat minHeight = [_columnHeightsArray[minHeightIndex] floatValue]; //求出行高
CGFloat lineHeight = [_delegate collectionView:self.collectionView layout:self minimumLineSpacingForSectionAtIndex:]; //上一次总的列高 加上 行高 加上新加上的item的height,才是现在这一列的总高度
//minHeight为最小列现在的高度
//lineHeight为行间距
//height为新加的item的高
_columnHeightsArray[minHeightIndex] = [NSNumber numberWithFloat:minHeight + lineHeight + height]; //重新算最小列高的下标
minHeightIndex = [self indexOfMinHeight]; //算下一次新加的item的x和y值
x = (spaceWidth + width) * minHeightIndex; y = [self minHeight];
}
} //重写这个方法,可以返回集合视图的总高度
- (CGSize)collectionViewContentSize
{
return CGSizeMake(self.collectionView.frame.size.width, [self maxHeight]);
} - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
return _attributesArray;
}

注意,最后一个方法的实现,即- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect,如果这个方法不写,集合视图是显示不出来的,这个方法是次保存的每个item的信息重新告诉集合视图,进行显示。

自定义UICollectinviewFlowLayout,即实现瀑布流的更多相关文章

  1. 自定义UICollectionViewLayout 布局实现瀑布流

    自定义 UICollectionViewLayout 布局,实现瀑布流:UICollectionView和UICollectionViewCell 另行创建,这只是布局文件, 外界控制器只要遵守协议并 ...

  2. 自定义基于jquery竖向瀑布流插件

    公司新项目做了一个关于图片的板块,网上找了一些瀑布流插件都不是很适合自己,于是就自己造轮子写一个,并封装成插件github 于是就想分享一下,主要是为了更好的学习与记忆. 如果大家进来了,希望能给我g ...

  3. iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流

    上篇博客的实例是自带的UICollectionViewDelegateFlowLayout布局基础上来做的Demo, 详情请看<iOS开发之窥探UICollectionViewControlle ...

  4. iOS---UICollectionView自定义流布局实现瀑布流效果

    自定义布局,实现瀑布流效果 自定义流水布局,继承UICollectionViewLayout 实现一下方法 // 每次布局之前的准备 - (void)prepareLayout; // 返回所有的尺寸 ...

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

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

  6. 自定义UICollectionLayout布局 —— UIKit之学习UICollectionView记录一《瀑布流》

    一.思路 思路一:比较每一行所有列的cell的高度,从上到下(也就是从第一行开始),从最短的开始计算,(记录下b的高度和索引,从开始计算,依次类推) 思路二:设置上.下.左.右间距和行间距.列间距及列 ...

  7. 自定义UICollectionViewLayout之瀑布流

    目标效果 因为系统给我们提供的 UICollectionViewFlowLayout 布局类不能实现瀑布流的效果,如果我们想实现 瀑布流 的效果,需要自定义一个 UICollectionViewLay ...

  8. android自定义viewgroup之我也玩瀑布流

    先看效果图吧, 继上一篇<android自定义viewgroup实现等分格子布局>中实现的布局效果,这里稍微有些区别,每个格子的高度不规则,就是传说的瀑布流布局,一般实现这种效果,要么用第 ...

  9. iOS自定义UICollectionViewLayout之瀑布流

    目标效果 因为系统给我们提供的 UICollectionViewFlowLayout 布局类不能实现瀑布流的效果,如果我们想实现 瀑布流 的效果,需要自定义一个 UICollectionViewLay ...

随机推荐

  1. clientX、pageX、scrollLeft、offsetLeft、clientWidth、screen.width的用法和区别

    一.定义和用法 1.event.clientX:事件对象的水平偏移量: event.clientY:事件对象的垂直偏移量: 2.event.pageX:事件对象加上滚动距离后的水平偏移量: event ...

  2. ABBYY PDF Transformer+怎么标志注释

    ABBYY PDF Transformer+是一款可创建.编辑.添加注释及将PDF文件转换为其他可编辑格式的通用工具,可用来在PDF页面的任何位置添加注释(关于如何通过ABBYY PDF Transf ...

  3. C语言实现简单php自定义扩展

    1.下载php源码 下载地址:http://cn2.php.net/get/php-5.6.29.tar.gz/from/this/mirror 传到/usr/local/src/下 上传命令:rz ...

  4. C# Marshal.GetActiveObject() 遭遇 HRESULT:0x800401E3 (MK_E_UNAVAILABLE))

    解决办法: 勿以管理员权限运行Visual Studio

  5. D 最熟悉的陌生人 (纪念当年就读的梅州市江南高级中学)

    最熟悉的陌生人 作者:张慧桥 “蝶恋花” 我匆匆地跟听众道了声再见,手忙脚乱地关掉了机器,拿出手机按下了一个快捷键…… “嘟…嘟…” 电话响两下后,我听到了那个我在睡梦中都可以认出来的声音. “你现在 ...

  6. ecmobile中IOS版本中界面文字不显示的解决

    查找以下方法. - (BOOL)setCurrentLanguageName:(NSString *)name{        BeeLanguage * lang = [self findLangu ...

  7. mybatis实战教程(mybatis in action)之四:实现关联数据的查询

    有了前面几章的基础,对一些简单的应用是可以处理的,但在实际项目中,经常是关联表的查询,比如最常见到的多对一,一对多等.这些查询是如何处理的呢,这一讲就讲这个问题.我们首先创建一个Article 这个表 ...

  8. union和union all的区别

    UNION 写一篇联合查询(把前后两个表的查询结果集合在前表中)首先有个为什么需要 相同记录数?? 记错了.应该是union两张表的查询字段数目要一致,字段类型要相似相同的数据类型,至少是相似,可转化 ...

  9. 【巩固】bootstrap笔记二

    这段主要记录如何给排版完的页面加一些动画效果,用到了的插件有: wow.min.js jquery.singlePageNav.min.js animate.css 将导航条上对应的菜单和页面上对应的 ...

  10. 函数指针_typedef

    一 函数指针 1 函数类型 函数的类型由它的返回值类型,和形参类型共通过决定,与函数名无关. eg:bool lengthcompare(const string&, const string ...