当前位置: 首页 > 编程日记 > 正文

iOS UICollectionView实现瀑布流(3)

前面两篇Blog简单的介绍了UICollection的基本使用并实现了类似Android的Gallery效果,这篇文章使用UICollection来实现瀑布流效果,代码主要是在极客学院Carol老师的视频,并在提供的demo下直接修改代码,进行屏幕适配,最终效果如下图




(1)ViewController.h文件

@interface ViewController : UIViewController<UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>
@property (nonatomic, strong) UICollectionView *collectionView;@end

ViewController.m文件

#import "ViewController.h"
#import "WaterFallFlowLayout.h"
#import "WaterFallUICollectionViewCell.h"
#define WIDTH ([UIScreen mainScreen].bounds.size.width-20)/3
CGFloat const kImageCount = 16;
static NSString *identifier = @"collectionView";
@interface ViewController ()
@property (nonatomic, strong) NSArray  *imageArr;
@end@implementation ViewController#pragma mark - 图片懒加载
-(NSArray*)imageArr{if (!_imageArr) {NSMutableArray *muArr = [NSMutableArray array];for (int i=1; i<=kImageCount; i++) {UIImage *image = [UIImage imageNamed:[[NSString alloc] initWithFormat:@"image%d",i]];[muArr addObject:image];}_imageArr = muArr;}return _imageArr;
}- (void)viewDidLoad {[super viewDidLoad];WaterFallFlowLayout *flowLayout = [[WaterFallFlowLayout alloc] init];self.collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:flowLayout];self.collectionView.backgroundColor = [UIColor redColor];self.collectionView.delegate = self;self.collectionView.dataSource = self;[self.collectionView registerClass:[WaterFallUICollectionViewCell class] forCellWithReuseIdentifier:identifier];[self.view addSubview:self.collectionView];
}#pragma mark - UICollectionView dataSource
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{return [self.imageArr count];
}-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{WaterFallUICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];cell.image = self.imageArr[indexPath.item];return cell;
}#pragma mark - 计算图片高度
-(float)imageHeight:(float)height width:(float)width{/*高度/宽度 = 压缩后高度/压缩后宽度*/float newHeight = height/width*(WIDTH);return newHeight;
}#pragma mark - cell大小
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{UIImage *imge = [self.imageArr objectAtIndex:indexPath.row];float height = [self imageHeight:imge.size.height width:imge.size.width];return CGSizeMake(WIDTH, height);
}#pragma mark - 边距
-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{UIEdgeInsets edgeInsets = {5,5,5,5};return edgeInsets;
}@end


(2)WaterFallFlowLayout.h文件

#import <UIKit/UIKit.h>@interface WaterFallFlowLayout : UICollectionViewFlowLayout
@property(nonatomic,assign)id<UICollectionViewDelegateFlowLayout> delegate;
@property(nonatomic,assign)NSInteger cellCount;//cell的个数
@property(nonatomic,strong)NSMutableArray *colArr;//存放列的高度
@property(nonatomic,strong)NSMutableDictionary *attributeDict;//cell的位置信息
@end


WaterFallFlowLayout.m文件
#import "WaterFallFlowLayout.h"
CGFloat const colCount = 3;
@implementation WaterFallFlowLayout
//准备布局:得到cell的总个数,为每个cell确定自己的位置
- (void)prepareLayout{[super prepareLayout];NSLog(@"prepareLayout");_colArr = [NSMutableArray array];_attributeDict = [NSMutableDictionary dictionary];self.delegate = (id<UICollectionViewDelegateFlowLayout>)self.collectionView.delegate;//获取cell的总个数_cellCount = [self.collectionView numberOfItemsInSection:0];if (_cellCount == 0) {return;}float top = 0;for (int i = 0; i < colCount; i++) {[_colArr addObject:[NSNumber numberWithFloat:top]];}//循环调用layoutForItemAtIndexPath方法,为每个cell布局,将indexPath传入,作为布局字典的key//layoutAttributesForItemAtIndexPath方法的实现,这里用到了一个布局字典,其实就是将每个cell的位置信息与indexPath相对应,将它们放到字典中,方便后面视图的检索for (int i = 0; i < _cellCount; i++) {[self layoutItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];}}//此方法会多次调用,为每个cell布局
- (void)layoutItemAtIndexPath:(NSIndexPath *)indexPath{//通过协议得到cell的间隙NSLog(@"layoutItemAtIndexPath");UIEdgeInsets edgeInsets = [self.delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:indexPath.row];CGSize itemSize = [self.delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];float col = 0;float shortHeight = [[_colArr objectAtIndex:col] floatValue];//找出高度最小的列,将cell加到最小列中for (int i = 0; i < _colArr.count; i++) {float height = [[_colArr objectAtIndex:i] floatValue];if (height < shortHeight) {shortHeight = height;col = i;}}float top = [[_colArr objectAtIndex:col] floatValue];NSLog(@"top:%f",top);//确定cell的frameCGRect frame = CGRectMake(edgeInsets.left + col * (edgeInsets.left + itemSize.width), top + edgeInsets.top, itemSize.width, itemSize.height);NSLog(@"frme:%f,%f,%f,%f",edgeInsets.left + col * (edgeInsets.left + itemSize.width),top + edgeInsets.top,itemSize.width,itemSize.height);//更新列高[_colArr replaceObjectAtIndex:col withObject:[NSNumber numberWithFloat:top + edgeInsets.top + itemSize.height]];//每个cell的frame对应一个indexPath,放入字典中[_attributeDict setObject:indexPath forKey:NSStringFromCGRect(frame)];
}- (NSArray *)indexPathsOfItem:(CGRect)rect{//遍历布局字典通过CGRectIntersectsRect方法确定每个cell的rect与传入的rect是否有交集,如果结果为true,则此cell应该显示,将布局字典中对应的indexPath加入数组NSLog(@"indexPathsOfItem");NSMutableArray *array = [NSMutableArray array];for (NSString *rectStr in _attributeDict) {CGRect cellRect = CGRectFromString(rectStr);if (CGRectIntersectsRect(cellRect, rect)) {NSIndexPath *indexPath = _attributeDict[rectStr];[array addObject:indexPath];}}return array;
}//返回cell的布局信息,如果忽略传入的rect一次性将所有的cell布局信息返回,图片过多时性能会很差
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{NSLog(@"layoutAttributesForElementsInRect");NSMutableArray *muArr = [NSMutableArray array];//indexPathsOfItem方法,根据传入的frame值计算当前应该显示的cellNSArray *indexPaths = [self indexPathsOfItem:rect];for (NSIndexPath *indexPath in indexPaths) {//  UICollectionViewLayoutAttributes *attribute = [self layoutAttributesForItemAtIndexPath:indexPath];UICollectionViewLayoutAttributes *attribute = [self layoutAttributesForItemAtIndexPath:indexPath];[muArr addObject:attribute];}return muArr;
}//返回每个CollectionViewCell的属性
-(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];for (NSString *rectStr in _attributeDict) {if (_attributeDict[rectStr]==indexPath) {attributes.frame = CGRectFromString(rectStr);}}return attributes;
}//最后还要实现这个方法,返回collectionView内容的大小
//只需要遍历前面创建的存放列高的数组得到列最高的一个作为高度返回就可以了
- (CGSize)collectionViewContentSize{NSLog(@"collectionViewContentSize");CGSize size = self.collectionView.frame.size;float maxHeight = [[_colArr objectAtIndex:0] floatValue];//查找最高的列的高度for (int i = 0; i < _colArr.count; i++) {float colHeight = [[_colArr objectAtIndex:i] floatValue];if (colHeight > maxHeight) {maxHeight = colHeight;}}size.height = maxHeight;return size;
}
@end


(3)WaterFallUICollectionViewCell.h文件

@interface WaterFallUICollectionViewCell : UICollectionViewCell
@property(nonatomic,strong) UIImage *image;
@end

WaterFallUICollectionViewCell.m文件

#import "WaterFallUICollectionViewCell.h"
#define WIDTH ([UIScreen mainScreen].bounds.size.width-20)/3@implementation WaterFallUICollectionViewCell
- (void)setImage:(UIImage *)image{if (_image != image) {_image = image;}[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect{float newHeight = _image.size.height / _image.size.width * WIDTH;[_image drawInRect:CGRectMake(0, 0, WIDTH, newHeight)];self.backgroundColor = [UIColor grayColor];
}@end

(4)运行测试


demo下载地址:http://download.csdn.net/detail/dolacmeng/8682759

相关文章:

LevelDb系列之简介

说起LevelDb也许您不清楚&#xff0c;但是如果作为IT工程师&#xff0c;不知道下面两位大神级别的工程师&#xff0c;那您的领导估计会Hold不住了&#xff1a;Jeff Dean和Sanjay Ghemawat。这两位是Google公司重量级的工程师&#xff0c;为数甚少的Google Fellow之二。 Jeff De…

Spark集群启动时worker节点启不起来

在spark集群中使用命令&#xff1a; sbin/start-all.sh 启动集群时报错&#xff1a; starting org.apache.spark.deploy.master.Master, logging to /home/yxk/cluster/spark/logs/spark-yxk-org.apache.spark.deploy.master.Master-1-linux.out yxklinuxs password: linux:…

XML xmlns

xmlns xml namespaces 参考 http://www.w3school.com.cn/tags/tag_prop_xmlns.asp http://www.w3school.com.cn/xml/xml_namespaces.asp <table><tr>这是一行</tr> </table><table><material>黄花梨</material> </table> 放到…

StarlingMVC简介,原理解说及示例源码

StarlingMVC简介 StarlingMVC是一个为使用Starling来开发游戏的MVC框架。这个框架的特性方面&#xff0c;很像Swiz和RobotLegs&#xff0c;原理亦像Mate。其特性列表如下&#xff1a; 依赖注入(DI)/控制反转(IOC)视图代理(View Mediation)事件捕获(Event Handling)非侵入性框架…

iOS调用系统相机文字改为中文

只要把这里改成China&#xff1a;

微服务项目的整合与测试

实验目的 掌握微服务项目的整合使用 掌握Swagger-UI的简单使用 练习内容 1、微服务项目整合 1.1、项目预览 1.1.1、在 https://github.com/shi469391tou/microservice-mallmanagement.git 地址下载&#xff0c;并导入Myeclipse中&#xff1b; 1.1.2、查看项目的结构 1.2、…

mysql单表多timestamp的current_timestamp设置问题

一个表中出现多个timestamp并设置其中一个为current_timestamp的时候经常会遇到 1293 - Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause 原因是当你给一个timestamp设置为on update current_time…

iOS 关于Blocks

*本文参考了《Objective-C高级编程 iOS与OSX多线程和内存管理》一书&#xff0c;关于Block的介绍摘取自此书。 Objective-c 语言中Block语法格式为&#xff1a; 返回值类型 参数列表 表达式 c语言中的函数语法格式为 返回值类型 函数方法名 参数列表 表达式 从上面的…

一步步写STM32 OS【二】环境搭建

一、安装IAR for ARM6.5 二、新建工程 1、选择处理器&#xff1a;STM32F407VG&#xff0c;暂不使用FPU2、必要的路径配置和宏定义3、使用SWO重定向IO输出4、使用ST-LINK仿真器5、下载配置6、设置CPU频率&#xff0c;防止SWO输出乱码三、代码调试 四、工程下载 stepbystep_stm32…

微服务项目的部署

练习目标 掌握Docker Compose编排工具的使用掌握微服务项目与Docker的整合方式掌握微服务项目的部署方式 项目整合参考&#xff1a;https://blog.csdn.net/qq_37823605/article/details/91379272 练习内容 1、Docker Compose编排工具 1.1、Docker Compose的安装与卸载 1.1…

CSS 布局:40个教程、技巧、例子和最佳实践

前言&#xff1a; 布局是WEB开发一个重要的课题&#xff0c;进入XHTML/CSS后&#xff0c;使用TABLE布局的方式逐渐淡出&#xff0c;CSS布局以众多优点成为主流&#xff0c;本文将介绍40个基于CSS的web布局的资源和教程。文章的出处在http://www.noupe.com/css/css-layouts-40-t…

【仿去哪儿登录】UITextField输入时检查输入框是否为空

APP登录时&#xff0c;一般是是等用户输入完账号和密码后才去检查是否为空&#xff0c;而去哪儿登录时&#xff0c;在账号和密码的输入过程中&#xff0c;只要当账号和密码其一为空时&#xff0c;登录按钮立即变成不可用&#xff08;图1&#xff09;&#xff0c;只有账号和密码…

sql排名语句

查询全部 select dwmc,pjdf,row_number() over(order by pjdf desc) as paiming from Sab_hhb_zhb inner join jgdx on jgdx.midSab_hhb_zhb.mid查询单个select paiming from (select mid,pjdf,row_number() over(order by pjdf desc) as paiming from Sab_hhb_zhb ) Sab_hhb_z…

Sqoop的基础应用

实验目的要求 了解ET了工具Sqoop&#xff1b;学会安装配置Sqoop&#xff1b;学会使用数据迁移框架Sqoop&#xff1b;使用Sqoop导入MySQL到HDFS和Hive&#xff1b;使用Sqoop导出HDFS数据到MySQL&#xff1b; 实验环境 Java jdk 1.7&#xff1b;apache-maven-3.6.0&#xff1b;…

hadoop程序MapReduce之SingletonTableJoin

需求&#xff1a;单表关联问题。从文件中孩子和父母的关系挖掘出孙子和爷奶关系 样板&#xff1a;child-parent.txt xiaoming daxiong daxiong alice daxiong jack 输出&#xff1a;xiaoming alice xiaoming jack 分析设计&#xff1a; mapper部分设计&#xff1a; 1、<k1,…

Android网络框架Volley的快速使用

一.基本使用 之前做Android开发都是使用学长自己封装好的网络请求框架&#xff0c;第三方网络框架也很多&#xff0c;网上搜索了一下&#xff0c;大多数人推荐使用 android-async-httpokhttpVolley 其中Volley是Google推出了官方的针对Android平台上的网络通信库&#xff0c;能…

浏览器版本过低

http://study.163.com/common/errors/notSupported.htm <div class"wb f-cb"> <a href"http://www.google.cn/intl/zh-CN/chrome/browser/" class"g f-hide" target"_blank">谷歌浏览器</a> <a href"http:/…

Spark的基础应用

目的要求 搭建Spark集群环境&#xff1b;Spark集群的启动、浏览与关闭&#xff1b;使用Eclipse编写Spark应用程序包&#xff1b;如何运行Spark任务&#xff1b; 实验环境 Java jdk 1.7&#xff1b;apache-maven-3.6.0&#xff1b;Eclipse&#xff1b;Apache_Hadoop集群&#…

HDU-2084 数塔 经典dp,水

1、HDU-2084 数塔 2、链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid2084 3、总结&#xff1a;从下往上推&#xff0c;最后归于顶点。方程为 dp[i][j] max(dp[i1][j],dp[i1][j1])a[i][j] #include<iostream> #include<cstring> #include<…

[16] 螺旋面(Spire)图形的生成算法

顶点数据的生成 1 bool YfBuildSpireVertices2 (3 Yreal radius, 4 Yreal assistRadius, 5 Yreal height, 6 Yuint slices,7 Yuint s…

iOS的页面跳转

1.通过NavigationController跳转 这个方式适用于根视图为NavigationController的控制器&#xff0c;首先&#xff0c;在storyboard中给跳转的目标控制器视图设置Identifier&#xff0c;名字自定&#xff0c;我这里直接使用Controller对应的名字&#xff0c;如图1&#xff1a;需…

最新Java面试题答案

JAVA基础 JAVA中的几种基本类型&#xff0c;各占用多少字节&#xff1f; 下图单位是bit,非字节 1B8bit String能被继承吗&#xff1f;为什么&#xff1f; 不可以&#xff0c;因为String类有final修饰符&#xff0c;而final修饰的类是不能被继承的&#xff0c;实现细节不允许改…

fedora装机后要运行的脚本(原创)

脚本:sh.sh 1 #!/bin/zsh2 #安装rpmfusion源3 dnf config-manager --add-repohttp://repo.fdzh.org/FZUG/FZUG.repo4 #安装一下有用的一些软件包5 yum -y install yum-fastestmirror 6 yum -y install unrar7 yum -y install thunderbird8 yum -y install emacs9 yum -y instal…

【Android】FragmentTabHost实现底部Tab菜单选项

以前实现类似微博底部菜单使用的是TabHostActivity来实现&#xff0c;但是使用的时候提醒已经被弃用&#xff0c;现在我们可以通过FragmentTabHostFragment来实现。下面就是demo&#xff1a; 1.main_activity.xml 主布局文件。 <LinearLayout xmlns:android"http://sc…

mysql远程访问,修改root密码

mysql -uroot -p #input password use mysql; update user set host% where userroot; flush privileges; #ok 密码root密码也可以改&#xff1a; 先停止正在运行的mysql实例&#xff0c;在配置文件/etc/my.cnf里面加入 skip-grant-tables&#xff0c; 重新启动Mysql 或者使用…

java面试题2019 答案

Java 面试随着时间的改变而改变。在过去的日子里&#xff0c;当你知道 String 和 StringBuilder 的区别&#xff08;String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象。因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String…

android layout analyze

adapterapientityhandleruiuntilwidgetappContent.java *************************************图片&#xff1a;drawable&#xff1a;存放各种位图文件&#xff0c;(.png&#xff0c;.jpg&#xff0c;.9png&#xff0c;.gif等)除此之外可能是一些其他的drawable类型的XML文件m…

【转】iOS开发学习计划

转自&#xff1a;简书 一、C语言基础 基本数据类型、基本运算、函数、数组、字符串、指针、结构体、预处理指令、枚举、文件操作、内存管理 二、Objective-C 1、Objective-C基本语法 数据类型、表达式、变量、循环结构、选择结构 2、Objective-C面向对象 类、对象、继承、自省…

[置顶] 单例模式lua实现

--[[优点一、实例控制单例模式会阻止其他对象实例化其自己的单例对象的副本&#xff0c;从而确保所有对象都访问唯一实例。二、灵活性因为类控制了实例化过程&#xff0c;所以类可以灵活更改实例化过程。缺点一、开销虽然数量很少&#xff0c;但如果每次对象请求引用时都要检查…

我在CSDN的第一个1024

1024程序员节日历史 2002年&#xff0c;俄罗斯程序员Valentin Balt收集签名&#xff0c;向俄罗斯联邦政府请愿将9月13日设定为程序员节。 2009年9月11日&#xff0c;俄罗斯总统梅德韦杰夫在节日安排方案上签了名&#xff0c;“程序员节”从此成为了俄罗斯的一个正式节日。除了俄…