自定义 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. (NO.00005)iOS实现炸弹人游戏(九):游戏主角(二)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 上篇介绍了游戏主角的初始化方法,下面我们一次来实现主角的其他方 ...

  2. 显示图像的SIFT flow描述子

    close all; % 模拟figure 5 im = zeros(401,401,3); im(:,:,:) = 0; im(2:200, 2:200, 2) = 255; im(202:400, ...

  3. Linux系统编程----孤儿进程

    什么是孤儿进程? 孤儿进程,  指在父进程退出后,而子进程还在运行,这个子进程就成了孤儿进程,这时由init进程(pid=1)接管 来看看例子: #include <stdio.h> #i ...

  4. Hibernate之多对多表,操作实例

    多表操作之多对多关系简介 思路就是: 在数据库底层通过添加中间表来指定关联关系. 在双方的实体中添加一个保存对方的集合 在双方的配置文件中使用set标签和many-to-many标签来进行关联关系的配 ...

  5. iOS中 最新支付宝支付(AliPay) 韩俊强的博客

    每日更新关注:http://weibo.com/hanjunqiang  新浪微博 现在的支付方式一般有三种, 支付宝, 微信, 网银. 个人觉得最简单易用的还是支付宝, 微信虽然看起来币支付宝要简单 ...

  6. 【一天一道LeetCode】#116. Populating Next Right Pointers in Each Node

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

  7. Windows7 x64 跨平台开发环境安装配置

    ======================================================================= Windows7 x64 跨平台开发环境安装配置 201 ...

  8. msm8974 camera driver添加新摄像头kernel hal修改

    添加一款新摄像头流程 1添加sensor kernel driver, 主要实现上电.rst.pwd.mclk等power setting,sensor prob & sensor  i2c ...

  9. RTB--Real TimeBidding模式的互联网广告(实时竞价的广告投放)

    RTB(real time bidding)实时竞价允许广告买家根据活动目标.目标人群以及费用门槛等因素对每一个广告及每次广告展示的费用进行竞价.竞价成功后获得广告展示机会,在展示位置上展示广告. 其 ...

  10. Java进阶(五)Junit测试

    我们在编写大型程序的时候,需要写成千上万个方法或函数,这些函数的功能可能很强大,但我们在程序中只用到该函数的一小部分功能,并且经过调试可以确定,这一小部分功能是正确的.但是,我们同时应该确保每一个函数 ...