第二十九篇、UICollectionView瀑布流
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瀑布流相关推荐
- 第二十九篇:故障处理流程
前言 故障处理流程大致可分为预防.发现.定位.止损几个大阶段,其中发现.定位.止损这三个阶段是处理故障现场的重要阶段,决定了处理故障的处理效率,能否在最短的时间内止损,故障处理效率也和我们的架构设计及 ...
- spring成神之路第二十九篇:BeanFactory 扩展(BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor)...
Spring中有2个非常重要的接口:BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,这2个接口面试中也会经常问到,本文我们一起 ...
- “约见”面试官系列之常见面试题第二十九篇之Vue和React的区别
vue与react的不同之处是什么?下面本篇文章就来给大家介绍一下.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助. vue与react,两者都为当下主流框架 相同之处在于: 使用 V ...
- Android UI开发第二十九篇——Android中五种常用的menu(菜单)
Android Menu在手机的应用中起着导航的作用,作者总结了5种常用的Menu. 1.左右推出的Menu 前段时间比较流行,我最早是在海豚浏览器中看到的,当时耳目一新.最早使用左右推出菜单的,听说 ...
- Android探索之旅(第二十九篇)手把手教你如何简单创建快应用
一个新鲜的事物出现我们程序猿们必须保持高度且灵敏的嗅觉,所以不妨我们就去大胆的放开去学习一下快应用,了解它的来龙去脉岂不美哉. 本文大多转载自@鸿洋,感谢对于知识的分享 一.环境搭建 1.安装node ...
- Android探索之旅(第二十九篇)QRCode终极秘术之三码合一(微信,QQ,支付宝)
然后就是傻瓜式操作 如果你感觉生产的二维码不够漂亮,你可以访问以下网址进行美化 官网地址
- 第二十九篇 ajax动态网页爬取,豆瓣电影,网易云音乐,千千音乐
心得:每天进步一点点,不懂得去查询,去学习,自己慢慢会进步的更多. 自己在学习过程中总结出来的爬虫的过程: 1.导入库,确定要用到的库 2.确定要爬取的url: 动态网页往往隐藏了在XHR,JS页面内 ...
- IntelliJ IDEA快速入门 | 第二十九篇:你应该知道的那些常用模板
简单了解一下IntelliJ IDEA中的模板 讲完快捷键以后,咱们接着往下讲,那讲什么呢?讲模板,模板的英文是Templates,那它是什么意思呢?模板的意思是我们可以配置一些常用的代码字母的缩写, ...
- NeHe OpenGL第二十九课:Blt函数
NeHe OpenGL第二十九课:Blt函数 Blitter 函数: 类似于DirectDraw的blit函数,过时的技术,我们有实现了它.它非常的简单,就是把一块纹理贴到另一块纹理上. 这篇文章是有 ...
- NeHe OpenGL教程 第二十九课:Blt函数
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
最新文章
- 荒唐!985高校规定研究生上课迟到两次就扣 500 元国家助学金!
- 直击5G的机遇与挑战,全新商业模式、规模化经济效益、最新技术进展…全解读...
- Linux下压力测试工具Webbench介绍
- vue分页tbale小荔枝
- 面向对象的三大特性之继承
- Android --- This project contains Java compilation errors,which can cause rendering failures for
- android studio 引入arr的问题
- oracle财务软件凭证打印,金算盘财务软件后台数据库为Oracle
- Linux中的软件源详解,linux软件管理构建本地源实例详解
- 马云经典语录:我不是传奇 我是平凡的人
- 微信小程序sass不编译怎么办_不吹牛,四款免费实用的微信小程序,打开立即使用!...
- 网页爬虫:零基础用爬虫爬取网页内容
- 英语对话关于计算机,有关电脑的一些英语对话
- java sqlite sqlite_busy_sqlite3出现SQLITE_BUSY错误码的原因以及解决方法
- Word插入的表格如何调整长和宽
- 【转】国家集训队论文分类
- 华为freebuds pro和airpods pro降噪对比 华为freebuds pro和airpods pro参数对比
- 怎么把所有图片变成一样的大小
- kafka(1) 初识
- 无线传感器网络路由协议AODV(Ad hoc on-demand distance vector routing)
热门文章
- 【luogu P3979 遥远的国度】 题解
- Linux 下MongoDb的安装
- .net 创建计划任务开机后自动以管理员身份启动运行 win7 ~ win10
- webapi net 直接更改协议头
- 打开与关闭Linux防火墙
- 用iframe框架,登录过期后登录框在框架里加载的问题
- android-常用布局-三
- 洛谷P2258 子矩阵——题解
- 未能正确加载包“Microsoft.Data.Entity.Design.Package.MicrosoftDataEntityDesignPackage
- Linux kernel中网络设备的管理