【iOS开发】collectionView 瀑布流实现
一、效果展示

二、思路分析
1> 布局的基本流程
当设置好collectionView的布局方式之后(UICollectionViewFlowLayout),当系统开始布局的时候,会调用 prepareLayout 来布局
- (void)prepareLayout;
与此同时,collectionViewCell 的每个控件的布局属性都会调用 以下方法来设置(可以重写方法来修改每个cell 的数值)
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
2> 每列 的高度计算方式
1.计算所有的cell 的高度,然后平均下来,得到itemSize 然后计算每列的高度-----> 该方法不够精确,而且极端情况下会相差太大
2.每次计算cell 的时候,找出高度最低的那一列,优先添加到该列,然后依次计算------> 该方法误差较小
Tip: 在collectionView中,contentSize 就是一个摆设,不能根据这个来计算 collectionView 的大小,系统会自动的根据 itemSize 来计算
三、核心代码实现
// // WaterFall.h // 瀑布流 // // Created by gxiangzi on 15/9/16. // Copyright © 2015年 hqu. All rights reserved. // #import <UIKit/UIKit.h> @interface WaterFall : UICollectionViewFlowLayout // 计算列数 @property (assign, nonatomic) NSInteger columCount; // 所有的模型数组 @property (strong, nonatomic) NSArray * dataList; @end
//
// WaterFall.m
// 瀑布流
//
// Created by gxiangzi on 15/9/16.
// Copyright © 2015年 hqu. All rights reserved.
//
/**
// 获得高度的办法
1. 计算总的高度,然后计算每个高度,最后设置itemsize 来计算
2. 找出最高的列,然后根据最高的列来计算
注意:collectionView 的contentView 是一个摆设,没有实际效果,需要根据 itemSize 来计算
*/
#import "WaterFall.h"
#import "Shop.h"
@interface WaterFall ()
@property (nonatomic,strong) NSMutableArray * itemsAttribute;
@end
@implementation WaterFall
-(void)prepareLayout
{
[super prepareLayout];
// self.sectionFootersPinToVisibleBounds = YES;
// 计算每列的宽度
CGFloat contentWidth = self.collectionView.bounds.size.width - self.sectionInset.left - self.sectionInset.right;
CGFloat colWidth = (contentWidth - (self.columCount - ) * self.minimumInteritemSpacing) / self.columCount;
self.minimumInteritemSpacing = ;
self.minimumLineSpacing = ;
[self attribute:colWidth];
}
- (void) attribute:(CGFloat) colWidth
{
NSInteger colCount[self.columCount];
CGFloat colHeight[self.columCount];
; i<self.columCount; ++i)
{
colHeight[i] = ;
colCount[i] = ;
}
// 定义总item高
CGFloat totoalItemHeight = ;
// 定义一个可变数组,来存储 素有的属性值
NSMutableArray * arrayM = [NSMutableArray arrayWithCapacity:self.dataList.count];
// 计数
NSInteger index = ;
// 遍历数组,计算相关的属性
for (Shop * shop in self.dataList)
{
// 1> 建立布局属性
NSIndexPath * indexPath = [NSIndexPath indexPathForRow:index inSection:];
index ++;
UICollectionViewLayoutAttributes * attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
// 2.计算当前的列数
// 计算是第几列
NSInteger col = [self shortestCol:colHeight];
// 计算每一列的个数
colCount[col]++;
// 3.计算frame
CGFloat w = shop.w;
CGFloat h = shop.h * colWidth / w;
CGFloat x = self.sectionInset.left + (colWidth + self.minimumInteritemSpacing) * col;
CGFloat y = colHeight[col] + self.minimumLineSpacing;
// 累加,计算同一列下一个元素的高度
colHeight[col] += (h + self.minimumLineSpacing);
attr.frame = CGRectMake(x, y, colWidth, h);
// 4.计算总的高度
totoalItemHeight += h;
// 5.添加到 itemsAttribute
[arrayM addObject:attr];
}
// 计算出最高的那一列
NSInteger highestCol = [self highestColL:colHeight];
// 设置 itemSize,使用总高度的平均值
self.itemSize = CGSizeMake(colWidth, (colHeight[highestCol]- colCount[highestCol] * self.minimumInteritemSpacing) / colCount[highestCol]);
// 添加页脚属性
UICollectionViewLayoutAttributes * footer = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter withIndexPath:[NSIndexPath indexPathForRow: inSection:]];
footer.frame = CGRectMake(, colHeight[highestCol], self.collectionView.bounds.size.width, );
[arrayM addObject:footer];
self.itemsAttribute = arrayM;
}
/// 返回所有 cell 的属性数组
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
return self.itemsAttribute;
}
/// 获得最少的那一列
///
/// @param colHeight 列高数组
///
/// @return 最少的列号
- (NSInteger) shortestCol:(CGFloat *)colHeight {
CGFloat min = MAXFLOAT;
CGFloat col = ;
; i<self.columCount; ++i)
{
if (colHeight[i] < min) {
min = colHeight[i];
col = i;
}
}
return col;
}
/// 获得最高的那一列
///
/// @param colHeight 列高数组
///
/// @return 最高的列号
- (NSInteger) highestColL:(CGFloat *)colHeight {
CGFloat max = ;
CGFloat col = ;
; i<self.columCount; ++i)
{
if(colHeight[i] > max)
{
max = colHeight[i];
col = i;
}
}
return col;
}
#pragma mark - 懒加载 属性数组
- (NSMutableArray *)itemsAttribute
{
if (_itemsAttribute == nil)
{
_itemsAttribute = [NSMutableArray array];
}
return _itemsAttribute;
}
@end
【iOS开发】collectionView 瀑布流实现的更多相关文章
- IOS开发之瀑布流照片墙实现
想必大家已经对互联网传统的照片布局方式司空见惯了,这种行列分明的布局虽然对用户来说简洁明了,但是长久的使用难免会产生审美疲劳.现在网上流行一种叫做“瀑布流”的照片布局样式,这种行与列参差不齐的状态着实 ...
- iOS之简单瀑布流的实现
iOS之简单瀑布流的实现 前言 超简单的瀑布流实现,这里说一下笔者的思路,详细代码在这里. 实现思路 collectionView能实现各中吊炸天的布局,其精髓就在于UICollectionVie ...
- iOS开发 - AVPlayer实现流音频边播边存
边播边下有三套左右实现思路,本文使用AVPlayer + AVURLAsset实现. 概述 1. AVPlayer简介 AVPlayer存在于AVFoundation中,可以播放视频和音频,可以理解为 ...
- iOS UITabView简写瀑布流
代码demo 一.tabViewCell,通过image的比例高算出cell 的高度 #import "TableViewCell.h" @implementation Table ...
- iOS开发之窥探UICollectionViewController(四) --一款功能强大的自定义瀑布流
在上一篇博客中<iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流>,自定义瀑布流的列数,Cell的外边距,C ...
- iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流
上篇博客的实例是自带的UICollectionViewDelegateFlowLayout布局基础上来做的Demo, 详情请看<iOS开发之窥探UICollectionViewControlle ...
- iOS开发笔记15:地图坐标转换那些事、block引用循环/weak–strong dance、UICollectionviewLayout及瀑布流、图层混合
1.地图坐标转换那些事 (1)投影坐标系与地理坐标系 地理坐标系使用三维球面来定义地球上的位置,单位即经纬度.但经纬度无法精确测量距离戒面积,也难以在平面地图戒计算机屏幕上显示数据.通过投影的方式可以 ...
- iOS开发:代码通用性以及其规范 第一篇(附带,自定义UITextView\进度条\双表显示\瀑布流 代码设计思路)
在iOS团队开发中,我见过一些人的代码,也修改过他们的代码.有的人的代码写的非常之规范.通用,几乎不用交流,就可以知道如何修改以及在它基础上扩展延生.有的人的代码写的很垃圾,一眼看过去,简直会怀疑自己 ...
- iOS开发-UICollectionView实现瀑布流
关于瀑布流的实现网上有很多种解法,自定义控件,TableView+ScrollView,UICollectionView是iOS6发布之后用于展示集合视图,算起来已经发布三年左右了,不过知识点是不变的 ...
随机推荐
- 开心系列学习笔记---------javascript(7)
一.函数 1)函数类型 函数声明(缩写为FD)是这样一种函数: 1.有一个特定的名称 2.在源码中的位置:要么处于程序级 ...
- DBA 思想天空笔记
/*+leading(t1) use_nl(t2*/这个HINT的含义,其中use_nl表示强制用嵌套循环连接方式.Leading(t1)表示强制先访问t1表,也就是t1表作为驱动表,增加HINT的目 ...
- MySQL加锁分析
参考:MySQL 加锁处理分析.该文已经讲的很详尽了,也易懂,下面仅仅是个人做的总结. 一. 背景 1.1 隔离级别 1.2 加锁过程 逐条处理,逐条加锁. 1.3 两阶段锁2PL 1.4 gap锁 ...
- (转载):() { :|:& }; : # <-- 打开终端,输入这个,回车.你看到了什么??
代码::() { :|:& }; : 为什么这个东西会让你的系统死掉???有人执行了然后问我 让我们来分析一下这段代码,我改一下格式,但内容是一样的 代码::() # 定义一个叫“:”的过程 ...
- 使用ViewPager实现左右“无限”滑动的万年历
有时候就是这样,研究一个问题,一开始想到了一个觉得可行的方案,然后去尝试:尝试了很久.很多次,已经要放弃了,关掉电脑心里 想这个需求没办法实现:在去上厕所的路上突然想到了一个点子,第二天一试,尼玛,搞 ...
- grok 添加字段
filter { grok { match =>[ "message","%{IPORHOST:clientip} \[%{HTTPDATE:time}\] \&q ...
- Jquery的bootstrap在线文本编辑器插件Summernote
http://www.jqcool.net/demo/201407/bootstrap-summernote/ Summernote是一个基于jquery的bootstrap超级简单WYSIWYG在线 ...
- POJ-2533最长上升子序列(DP+二分)(优化版)
Longest Ordered Subsequence Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 41944 Acc ...
- javascrpit开发连连看记录-小游戏
工作之余,总想做点什么有意思的东西.但是苦于不知道做什么,也就一直没有什么动作.在一个午饭后,跟@jedmeng和@墨尘聊天过程中,发现可以写一些小东西来练练手,有以下几点好处: 1. ...
- linux group
groups 查看当前登录用户的组内成员 groups gliethttp 查看gliethttp用户所在的组,以及组内成员 whoami 查看当前登录用户名 /etc/group文件包含所有组 ...