自定义 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 布局实现瀑布流的更多相关文章

  1. OC - 29.自定义布局实现瀑布流

    概述 瀑布流是电商应用展示商品通常采用的一种方式,如图示例 瀑布流的实现方式,通常有以下几种 通过UITableView实现(不常用) 通过UIScrollView实现(工作量较大) 通过UIColl ...

  2. 自定义基于jquery竖向瀑布流插件

    公司新项目做了一个关于图片的板块,网上找了一些瀑布流插件都不是很适合自己,于是就自己造轮子写一个,并封装成插件github 于是就想分享一下,主要是为了更好的学习与记忆. 如果大家进来了,希望能给我g ...

  3. flex布局实现瀑布流排版

    网上有很多有关js(jq)实现瀑布流和有关瀑布流的插件很多,例如:插件(Masonry,Wookmark等等).按照正常的逻辑思维,瀑布流的排版(item列表)一般都是 由左到右,上而下排序的结果,单 ...

  4. 纯 css column 布局实现瀑布流效果

    原理 CSS property: columns.CSS属性 columns 用来设置元素的列宽和列数. 兼容性 chrome 50+ IE 10+ android browser 2.1+ with ...

  5. 自定义UICollectionViewLayout之瀑布流

    目标效果 因为系统给我们提供的 UICollectionViewFlowLayout 布局类不能实现瀑布流的效果,如果我们想实现 瀑布流 的效果,需要自定义一个 UICollectionViewLay ...

  6. iOS自定义UICollectionViewLayout之瀑布流

    目标效果 因为系统给我们提供的 UICollectionViewFlowLayout 布局类不能实现瀑布流的效果,如果我们想实现 瀑布流 的效果,需要自定义一个 UICollectionViewLay ...

  7. iOS 瀑布流之栅格布局

    代码地址如下:http://www.demodashi.com/demo/14760.html 一 .效果预览 二.确定需求 由下面的需求示意图可知模块的最小单位是正方形,边长是屏幕宽除去边距间隔后的 ...

  8. 详解纯css实现瀑布流(multi-column多列及flex布局)

    瀑布流的布局自我感觉还是很吸引人的,最近又看到实现瀑布流这个做法,在这里记录下,特别的,感觉flex布局实现瀑布流还是有点懵的样子,不过现在就可以明白它的原理了 1.multi-column多列布局实 ...

  9. css3多列布局瀑布流加载样式

    看了一些网站的瀑布流加载,正好看到css3的多列属性,尝试着写了一个css做布局的瀑布流. 直接上代码: <!DOCTYPE html> <html lang="en&qu ...

随机推荐

  1. iOS让软键盘消失的简单方法

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 一些文本输入控件等待输入时会弹出软键盘,我们可以设置这些控件的 ...

  2. 1.QT中播放视频,录音程序的编写

     1  通过process的方式播放视频 T22VideoPlayer.pro HEADERS += \ MyWidget.h SOURCES += \ MyWidget.cpp QT += gu ...

  3. Redis简介以及数据类型存储

    由于我们在大型互联网项目当中,用户访问量比较大,比较多,会产生并发问题,对于此,我们该如何解决呢,Redis横空出世,首先,我们来简单的认识一下Redis,详细介绍如下所示: Redis是一个开源的, ...

  4. ajax核心技术1---XMLHttpRequset对象的使用

    AJAX即"Asynchronous Javascript And XML"(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术.AJAX = 异步 Ja ...

  5. 概率论:假设检验-t检验和Augmented Dickey–Fuller test

    http://blog.csdn.net/pipisorry/article/details/51184556 T检验 T检验,亦称student t检验(Student's t test),学生t检 ...

  6. 【一天一道LeetCode】#242. Valid Anagram

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given t ...

  7. SpringMVC源码分析--容器初始化(四)FrameworkServlet

    在上一篇博客SpringMVC源码分析--容器初始化(三)HttpServletBean我们介绍了HttpServletBean的init函数,其主要作用是初始化了一下SpringMVC配置文件的地址 ...

  8. [rrdtool]监控和自动画图,简单的监控.md

    现在想要监控服务的流量和并发数,可是又没那么多时间来写系统,其他的运维系统又不熟悉,于是就用现有的rrdtool shell做了个简单的监控界面,临时用下,也算是个小实验把. rrdtool也是刚接触 ...

  9. Mybatis执行SimpleExecutor(三)

    SimpleExecutor通过类名可以看出,它是一个简单的执行类,并不会做一些处理就执行sql,源码及分析如下: /** * @author Clinton Begin */ public clas ...

  10. Gradle实现的两种简单的多渠道打包方法

    本来计划今天发Android的官方技术文档的翻译--<Gradle插件用户指南>的第五章的,不过由于昨天晚上没译完,还差几段落,所以只好推后了. 今天就说一下使用Gradle进行类似友盟这 ...