1.实现思路

  >第一种方案:UIScrollView 镶嵌三个UITableView (不推荐使用)

  >第二种方案:UIScrollView 镶嵌UIImageView (需要解决循环利用的问题)

  >第三种方案:UICollectionView

2.基本骨架Layout:需要重写的方法

1)- (void)prepareLayout
2)- (CGSize)collectionViewContentSize
3)- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
4)- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

.h

#import <UIKit/UIKit.h>@class JQWaterflowLayout;@protocol JQWaterflowLayoutDelegate <NSObject>
@required
- (CGFloat)waterflowLayout:(JQWaterflowLayout *)waterflowLayout heightForItemAtIndex:(NSUInteger)index itemWidth:(CGFloat)itemWidth;@optional
- (CGFloat)columnCountInWaterflowLayout:(JQWaterflowLayout *)waterflowLayout;
- (CGFloat)columnMarginInWaterflowLayout:(JQWaterflowLayout *)waterflowLayout;
- (CGFloat)rowMarginInWaterflowLayout:(JQWaterflowLayout *)waterflowLayout;
- (UIEdgeInsets)edgeInsetsInWaterflowLayout:(JQWaterflowLayout *)waterflowLayout;
@end@interface JQWaterflowLayout : UICollectionViewLayout
/** 代理 */
@property (nonatomic, weak) id<JQWaterflowLayoutDelegate> delegate;
@end

.m

#import "XMGWaterflowLayout.h"/** 默认的列数 */
static const NSInteger JQDefaultColumnCount = 3;
/** 每一列之间的间距 */
static const CGFloat JQDefaultColumnMargin = 10;
/** 每一行之间的间距 */
static const CGFloat JQDefaultRowMargin = 10;
/** 边缘间距 */
static const UIEdgeInsets JQDefaultEdgeInsets = {10, 10, 10, 10};@interface JQWaterflowLayout()
/** 存放所有cell的布局属性 */
@property (nonatomic, strong) NSMutableArray *attrsArray;
/** 存放所有列的当前高度 */
@property (nonatomic, strong) NSMutableArray *columnHeights;
/** 内容的高度 */
@property (nonatomic, assign) CGFloat contentHeight;- (CGFloat)rowMargin;
- (CGFloat)columnMargin;
- (NSInteger)columnCount;
- (UIEdgeInsets)edgeInsets;
@end@implementation JQWaterflowLayout#pragma mark - 常见数据处理
- (CGFloat)rowMargin
{if ([self.delegate respondsToSelector:@selector(rowMarginInWaterflowLayout:)]) {return [self.delegate rowMarginInWaterflowLayout:self];} else {return JQDefaultRowMargin;}
}- (CGFloat)columnMargin
{if ([self.delegate respondsToSelector:@selector(columnMarginInWaterflowLayout:)]) {return [self.delegate columnMarginInWaterflowLayout:self];} else {return JQDefaultColumnMargin;}
}- (NSInteger)columnCount
{if ([self.delegate respondsToSelector:@selector(columnCountInWaterflowLayout:)]) {return [self.delegate columnCountInWaterflowLayout:self];} else {return JQDefaultColumnCount;}
}- (UIEdgeInsets)edgeInsets
{if ([self.delegate respondsToSelector:@selector(edgeInsetsInWaterflowLayout:)]) {return [self.delegate edgeInsetsInWaterflowLayout:self];} else {return JQDefaultEdgeInsets;}
}#pragma mark - 懒加载
- (NSMutableArray *)columnHeights
{if (!_columnHeights) {_columnHeights = [NSMutableArray array];}return _columnHeights;
}- (NSMutableArray *)attrsArray
{if (!_attrsArray) {_attrsArray = [NSMutableArray array];}return _attrsArray;
}/*** 初始化*/
- (void)prepareLayout
{[super prepareLayout];self.contentHeight = 0;// 清除以前计算的所有高度
    [self.columnHeights removeAllObjects];for (NSInteger i = 0; i < self.columnCount; i++) {[self.columnHeights addObject:@(self.edgeInsets.top)];}// 清除之前所有的布局属性
    [self.attrsArray removeAllObjects];// 开始创建每一个cell对应的布局属性NSInteger count = [self.collectionView numberOfItemsInSection:0];for (NSInteger i = 0; i < count; i++) {// 创建位置NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];// 获取indexPath位置cell对应的布局属性UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];[self.attrsArray addObject:attrs];}
}/*** 决定cell的排布*/
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{return self.attrsArray;
}/*** 返回indexPath位置cell对应的布局属性*/
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{// 创建布局属性UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];// collectionView的宽度CGFloat collectionViewW = self.collectionView.frame.size.width;// 设置布局属性的frameCGFloat w = (collectionViewW - self.edgeInsets.left - self.edgeInsets.right - (self.columnCount - 1) * self.columnMargin) / self.columnCount;CGFloat h = [self.delegate waterflowLayout:self heightForItemAtIndex:indexPath.item itemWidth:w];// 找出高度最短的那一列NSInteger destColumn = 0;CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];for (NSInteger i = 1; i < self.columnCount; i++) {// 取得第i列的高度CGFloat columnHeight = [self.columnHeights[i] doubleValue];if (minColumnHeight > columnHeight) {minColumnHeight = columnHeight;destColumn = i;}}CGFloat x = self.edgeInsets.left + destColumn * (w + self.columnMargin);CGFloat y = minColumnHeight;if (y != self.edgeInsets.top) {y += self.rowMargin;}attrs.frame = CGRectMake(x, y, w, h);// 更新最短那列的高度self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame));// 记录内容的高度CGFloat columnHeight = [self.columnHeights[destColumn] doubleValue];if (self.contentHeight < columnHeight) {self.contentHeight = columnHeight;}return attrs;
}- (CGSize)collectionViewContentSize
{
//    CGFloat maxColumnHeight = [self.columnHeights[0] doubleValue];
//    for (NSInteger i = 1; i < self.columnCount; i++) {
//        // 取得第i列的高度
//        CGFloat columnHeight = [self.columnHeights[i] doubleValue];
//
//        if (maxColumnHeight < columnHeight) {
//            maxColumnHeight = columnHeight;
//        }
//    }return CGSizeMake(0, self.contentHeight + self.edgeInsets.bottom);
}@end

转载于:https://www.cnblogs.com/HJQ2016/p/5881248.html

第二十九篇、UICollectionView瀑布流相关推荐

  1. 第二十九篇:故障处理流程

    前言 故障处理流程大致可分为预防.发现.定位.止损几个大阶段,其中发现.定位.止损这三个阶段是处理故障现场的重要阶段,决定了处理故障的处理效率,能否在最短的时间内止损,故障处理效率也和我们的架构设计及 ...

  2. spring成神之路第二十九篇:BeanFactory 扩展(BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor)...

    Spring中有2个非常重要的接口:BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,这2个接口面试中也会经常问到,本文我们一起 ...

  3. “约见”面试官系列之常见面试题第二十九篇之Vue和React的区别

    vue与react的不同之处是什么?下面本篇文章就来给大家介绍一下.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助. vue与react,两者都为当下主流框架 相同之处在于: 使用 V ...

  4. Android UI开发第二十九篇——Android中五种常用的menu(菜单)

    Android Menu在手机的应用中起着导航的作用,作者总结了5种常用的Menu. 1.左右推出的Menu 前段时间比较流行,我最早是在海豚浏览器中看到的,当时耳目一新.最早使用左右推出菜单的,听说 ...

  5. Android探索之旅(第二十九篇)手把手教你如何简单创建快应用

    一个新鲜的事物出现我们程序猿们必须保持高度且灵敏的嗅觉,所以不妨我们就去大胆的放开去学习一下快应用,了解它的来龙去脉岂不美哉. 本文大多转载自@鸿洋,感谢对于知识的分享 一.环境搭建 1.安装node ...

  6. Android探索之旅(第二十九篇)QRCode终极秘术之三码合一(微信,QQ,支付宝)

    然后就是傻瓜式操作 如果你感觉生产的二维码不够漂亮,你可以访问以下网址进行美化 官网地址

  7. 第二十九篇 ajax动态网页爬取,豆瓣电影,网易云音乐,千千音乐

    心得:每天进步一点点,不懂得去查询,去学习,自己慢慢会进步的更多. 自己在学习过程中总结出来的爬虫的过程: 1.导入库,确定要用到的库 2.确定要爬取的url: 动态网页往往隐藏了在XHR,JS页面内 ...

  8. IntelliJ IDEA快速入门 | 第二十九篇:你应该知道的那些常用模板

    简单了解一下IntelliJ IDEA中的模板 讲完快捷键以后,咱们接着往下讲,那讲什么呢?讲模板,模板的英文是Templates,那它是什么意思呢?模板的意思是我们可以配置一些常用的代码字母的缩写, ...

  9. NeHe OpenGL第二十九课:Blt函数

    NeHe OpenGL第二十九课:Blt函数 Blitter 函数: 类似于DirectDraw的blit函数,过时的技术,我们有实现了它.它非常的简单,就是把一块纹理贴到另一块纹理上. 这篇文章是有 ...

  10. NeHe OpenGL教程 第二十九课:Blt函数

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

最新文章

  1. 荒唐!985高校规定研究生上课迟到两次就扣 500 元国家助学金!
  2. 直击5G的机遇与挑战,全新商业模式、规模化经济效益、最新技术进展…全解读...
  3. Linux下压力测试工具Webbench介绍
  4. vue分页tbale小荔枝
  5. 面向对象的三大特性之继承
  6. Android --- This project contains Java compilation errors,which can cause rendering failures for
  7. android studio 引入arr的问题
  8. oracle财务软件凭证打印,金算盘财务软件后台数据库为Oracle
  9. Linux中的软件源详解,linux软件管理构建本地源实例详解
  10. 马云经典语录:我不是传奇 我是平凡的人
  11. 微信小程序sass不编译怎么办_不吹牛,四款免费实用的微信小程序,打开立即使用!...
  12. 网页爬虫:零基础用爬虫爬取网页内容
  13. 英语对话关于计算机,有关电脑的一些英语对话
  14. java sqlite sqlite_busy_sqlite3出现SQLITE_BUSY错误码的原因以及解决方法
  15. Word插入的表格如何调整长和宽
  16. 【转】国家集训队论文分类
  17. 华为freebuds pro和airpods pro降噪对比 华为freebuds pro和airpods pro参数对比
  18. 怎么把所有图片变成一样的大小
  19. kafka(1) 初识
  20. 无线传感器网络路由协议AODV(Ad hoc on-demand distance vector routing)

热门文章

  1. 【luogu P3979 遥远的国度】 题解
  2. Linux 下MongoDb的安装
  3. .net 创建计划任务开机后自动以管理员身份启动运行 win7 ~ win10
  4. webapi net 直接更改协议头
  5. 打开与关闭Linux防火墙
  6. 用iframe框架,登录过期后登录框在框架里加载的问题
  7. android-常用布局-三
  8. 洛谷P2258 子矩阵——题解
  9. 未能正确加载包“Microsoft.Data.Entity.Design.Package.MicrosoftDataEntityDesignPackage
  10. Linux kernel中网络设备的管理