自定义UICollectionViewLayout 布局实现瀑布流
自定义 UICollectionViewLayout 布局,实现瀑布流;UICollectionView和UICollectionViewCell 另行创建,这只是布局文件,
外界控制器只要遵守协议并成为他的代理并实现代理方法heightForItemAtIndex:返回每个cell的高就可以实现温布流效果,也
可以实现相应的代理方法设置总共有多少列或是行间距列间距与边框间距。
ViewLayout.h 文件:
#import <UIKit/UIKit.h>
@class ViewLayout;
@protocol ViewLayoutDelegate <NSObject>
// 必须需要实现的代理方法
@required
/** 返回 index 位置的item的高 */
- (CGFloat)viewLayout:(ViewLayout *)ViewLayout heightForItemAtIndex:(NSInteger)index width:(CGFloat)width;
// 可选实现的代理方法
@optional
/** 返回 ViewLayout 布局的最大例数代理方法 */
- (CGFloat)numberOfMaxColumnInViewLayout:(ViewLayout *)viewLayout;
/** 返回 ViewLayout 布局每列的间距代理方法 */
- (CGFloat)numberOfColumnMarginInViewLayout:(ViewLayout *)viewLayout;
/** 返回 ViewLayout 布局的行间距代理方法 */
- (CGFloat)numberOfRowMarginInViewLayout:(ViewLayout *)viewLayout;
/** 返回 ViewLayout 布局的上左下右边框间距代理方法 */
- (UIEdgeInsets)edgeInsetsOfEdgeInViewLayout:(ViewLayout *)viewLayout;
@end
@interface ViewLayout : UICollectionViewLayout
/** ViewLayout 代理属性 */
@property (nonatomic, weak) id <ViewLayoutDelegate> delegate;
@end
ViewLayout.m 文件:
#import "ViewLayout.h"
/** 默认最大例数 */
static const NSInteger defaultMaxColumn = 3;
/** 默认例间距 */
static const CGFloat defaultdefaultColumnMargin = 10;
/** 默认行间距 */
static const CGFloat defaultdefaultRowMargin = 10;
/** 默认边框间距 */
static const UIEdgeInsets defaultEdgeInsets = {10, 10 ,10, 10};
@interface ViewLayout ()
/** 装有所有的布局性的数组 */
@property (nonatomic, strong) NSMutableArray *attributesArray;
/** 装有所有有例的高度 */
@property (nonatomic, strong) NSMutableArray *columnHeights;
//方法声明
- (CGFloat)maxColumn;
- (CGFloat)columnMargin;
- (CGFloat)rowMargin;
- (UIEdgeInsets)edgeInsets;
@end
@implementation ViewLayout
/** 返回最大列数 方法实现*/
- (CGFloat)maxColumn{
if ([self.delegate respondsToSelector:@selector(numberOfMaxColumnInViewLayout:)]) {
return [self.delegate numberOfMaxColumnInViewLayout:self];
}else{
return defaultMaxColumn;
}
}
/** 返回列间距 方法实现*/
- (CGFloat)columnMargin{
if ([self.delegate respondsToSelector:@selector(numberOfColumnMarginInViewLayout:)]) {
return [self.delegate numberOfColumnMarginInViewLayout:self];
}else{
return defaultdefaultColumnMargin;
}
}
/** 行间距 方法实现*/
- (CGFloat)rowMargin{
if ([self.delegate respondsToSelector:@selector(numberOfRowMarginInViewLayout:)]) {
return [self.delegate numberOfRowMarginInViewLayout:self];
}else{
return defaultdefaultRowMargin;
}
}
/** 边框的间距 方法实现*/
- (UIEdgeInsets)edgeInsets{
if ([self.delegate respondsToSelector:@selector(edgeInsetsOfEdgeInViewLayout:)]) {
return [self.delegate edgeInsetsOfEdgeInViewLayout:self];
}else{
return defaultEdgeInsets;
}
}
- (NSMutableArray *)attributesArray{
if (!_attributesArray) {
_attributesArray = [NSMutableArray array];
}
return _attributesArray;
}
- (NSMutableArray *)columnHeights{
if (!_columnHeights) {
_columnHeights = [NSMutableArray array];
}
return _columnHeights;
}
// 准备开始布局时调用方法
- (void)prepareLayout{
[super prepareLayout];
[self.columnHeights removeAllObjects];
[self.attributesArray removeAllObjects];
//先初始给装有所有例高数组赋值
for (int i = 0; i < self.maxColumn; ++i) {
self.columnHeights[i] = @(self.edgeInsets.top);
}
//获取第总共的cell数量
NSInteger count = [self.collectionView numberOfItemsInSection:0];
//有 for循环为每为个 cell添加布局属性
for (int i = 0; i < count; ++i) {
//创建第 i 个位置索引
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
//根据索引创建布局属性
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
[self.attributesArray addObject:attributes];
}
}
// 返回所有元素的布局属性数组
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
return self.attributesArray;
}
// 返回 索引 indexPath 位置的cell的布属性
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
CGFloat width = self.collectionView.bounds.size.width;
CGFloat w = (width - self.edgeInsets.left - self.edgeInsets.right - ((self.maxColumn - 1) * self.columnMargin)) / self.maxColumn;
// 执行代理方法 拿到代理方法返回的高度
CGFloat h = [self.delegate viewLayout:self heightForItemAtIndex:indexPath.item width:w];
// 找出最短的那一例的高和例号
CGFloat miniHeight = [self.columnHeights[0] doubleValue]; //先初始默认数组中第0个元素最小值
NSInteger miniColumn = 0; //初始默认最小例号
for (int i = 1; i < self.maxColumn; ++i) {
CGFloat height = [self.columnHeights[i] doubleValue];
if (miniHeight > height) {
miniHeight = height;
miniColumn = i;
}
}
CGFloat x = self.edgeInsets.left + miniColumn * (w + self.columnMargin);
CGFloat y = miniHeight;
if (y != self.edgeInsets.top) {
y += self.rowMargin;
}
attributes.frame = CGRectMake(x, y, w, h);
//保存更新当前高到对应例的数组
self.columnHeights[miniColumn] = @(CGRectGetMaxY(attributes.frame));
return attributes;
}
// collectionView的滚动范围
- (CGSize)collectionViewContentSize{
//找出最高的所在例
CGFloat maxHeight = 0; //初始最大高为 0
for (int i = 0; i < self.maxColumn; ++i) {
CGFloat height = [self.columnHeights[i] doubleValue];
if (maxHeight < height) {
maxHeight = height;
}
}
return CGSizeMake(0, maxHeight + self.edgeInsets.bottom);
}
@end
自定义UICollectionViewLayout 布局实现瀑布流的更多相关文章
- OC - 29.自定义布局实现瀑布流
概述 瀑布流是电商应用展示商品通常采用的一种方式,如图示例 瀑布流的实现方式,通常有以下几种 通过UITableView实现(不常用) 通过UIScrollView实现(工作量较大) 通过UIColl ...
- 自定义基于jquery竖向瀑布流插件
公司新项目做了一个关于图片的板块,网上找了一些瀑布流插件都不是很适合自己,于是就自己造轮子写一个,并封装成插件github 于是就想分享一下,主要是为了更好的学习与记忆. 如果大家进来了,希望能给我g ...
- flex布局实现瀑布流排版
网上有很多有关js(jq)实现瀑布流和有关瀑布流的插件很多,例如:插件(Masonry,Wookmark等等).按照正常的逻辑思维,瀑布流的排版(item列表)一般都是 由左到右,上而下排序的结果,单 ...
- 纯 css column 布局实现瀑布流效果
原理 CSS property: columns.CSS属性 columns 用来设置元素的列宽和列数. 兼容性 chrome 50+ IE 10+ android browser 2.1+ with ...
- 自定义UICollectionViewLayout之瀑布流
目标效果 因为系统给我们提供的 UICollectionViewFlowLayout 布局类不能实现瀑布流的效果,如果我们想实现 瀑布流 的效果,需要自定义一个 UICollectionViewLay ...
- iOS自定义UICollectionViewLayout之瀑布流
目标效果 因为系统给我们提供的 UICollectionViewFlowLayout 布局类不能实现瀑布流的效果,如果我们想实现 瀑布流 的效果,需要自定义一个 UICollectionViewLay ...
- iOS 瀑布流之栅格布局
代码地址如下:http://www.demodashi.com/demo/14760.html 一 .效果预览 二.确定需求 由下面的需求示意图可知模块的最小单位是正方形,边长是屏幕宽除去边距间隔后的 ...
- 详解纯css实现瀑布流(multi-column多列及flex布局)
瀑布流的布局自我感觉还是很吸引人的,最近又看到实现瀑布流这个做法,在这里记录下,特别的,感觉flex布局实现瀑布流还是有点懵的样子,不过现在就可以明白它的原理了 1.multi-column多列布局实 ...
- css3多列布局瀑布流加载样式
看了一些网站的瀑布流加载,正好看到css3的多列属性,尝试着写了一个css做布局的瀑布流. 直接上代码: <!DOCTYPE html> <html lang="en&qu ...
随机推荐
- java中小数的处理:高精度运算用bigDecimal类,精度保留方法,即舍入方式的指定
一. 计算机的小数计算一定范围内精确,超过范围只能取近似值: 计算机存储的浮点数受存储bit位数影响,只能保证一定范围内精准,超过bit范围的只能取近似值. java中各类型的精度范围参见:http: ...
- 1.QT中的容器QVector,QList,QSet,QMap,QQueue,QStack,QMultiMap,QSingleList等
1 新建一个项目 在pro文件中只需要加上CONFIG += C++11 main.cpp #include <QMap> int main() { QMap<int,QStrin ...
- Oracle启用scott用户
先查询一下目前数据库是否有scott用户 select username,account_status from dba_users where username like '%SCOTT%'; 如果 ...
- C语言--测试电脑存储模式(大端存储OR小端存储)
相信大家都知道大端存储和小端存储的概念,这在平时,我们一般不用考虑,但是,在某些场合,这些概念就显得很重要,比如,在 Socket 通信时,我们的电脑是小端存储模式,可是传送数据或者消息给对方电脑时, ...
- Android进阶(三)android httpClient 支持HTTPS的访问方式
项目中Android https请求地址遇到了这个异常(无终端认证): javax.net.ssl.SSLPeerUnverifiedException: No peer certificate 是S ...
- C# 运行时序列化
一. 序列化与反序列的作用 为什么要有序列化呢,考虑下面这种情况,在WINFORM或者更为方便的WPF工程中,当我们进行UI设计时,可以随意的将一个控件剪切/张贴到另外一个地方.操作方便的背后是什么在 ...
- String之常量池小结
1.String 常量池 String使用private final char value[ ]实现字符串的存储,也就是说String创建对象之后不能够再次修改此对象中存储的字符串内容,因而Strin ...
- 图文浅析APK程序运行的过程
概述 APK程序运行过程有别于FrameWork底层启动过程,它们是倆码事,本文将以图文方式总结一下APK启动的过程,主要分为一下部分 [1]基本概念 [2]APK过程 1 .新的知识点 [1]什么是 ...
- Linux常用的网络命令
这些命令都是我在浏览网页的时候偶然看到的,但是不太完整,所以我就整理了一下,详见如下. 1.查看网络接口状态 ifconfig(interface configuration,接口配置),通常会加上- ...
- Socket编程实践(2) --Socket编程导引
什么是Socket? Socket可以看成是用户进程与内核网络协议栈的接口(编程接口, 如下图所示), 其不仅可以用于本机进程间通信,可以用于网络上不同主机的进程间通信, 甚至还可以用于异构系统之间的 ...