当前位置: 首页 > news >正文

iOS开发:瀑布流效果的实现(使用UICollectionView)

iOS开发:瀑布流的实现

图片描述

效果的实现,主要是对UICollectionViewLayout进行封装,我的.h文件中:

#import <UIKit/UIKit.h>
@class CustomeViewLayout;
@protocol CustomViewLayoutDelegate <NSObject>

/**
 计算item高度的代理方法,将item的高度与indexPath传给外界
 */
- (CGFloat)customFallLayout:(CustomeViewLayout *)customFallLayout itemHeightForWidth:(CGFloat)itemWidth atIndexPath:(NSIndexPath *)indexPath;

@end

//实现了瀑布流功能,但是不能添加头部和底部视图,如项目中有添加头部或底部视图的需求,请慎用!!!
@interface CustomeViewLayout : UICollectionViewLayout

/**
 总列数,默认是2
 */
@property (nonatomic, assign) NSInteger columnCount;

/**
 列间距,默认是0
 */
@property (nonatomic, assign) float columnSpacing;

/**
 行间距,默认是0
 */
@property (nonatomic, assign) float rowSpacing;

/**
 section与CollectionView的间距,上、左、下、右,默认是(0, 0, 0, 0)
 */
@property (nonatomic, assign) UIEdgeInsets sectionInset;

/**
 同时设置列间距、行间距、sectionInset

 @param columnSpacing 列间距
 @param rowSpacing 行间距
 @param sectionInset 设置上、左、下、右的距离
 */
- (void)setColumnSpacing:(float)columnSpacing rowSpacing:(float)rowSpacing sectionInset:(UIEdgeInsets)sectionInset;

#pragma mark ====== 代理方法、block二选其一 ======
/**
 一下代理属性与block属性二选其一,用来设置每一个item的高度
 会将item的高度与indexPath传递给外界
 如果两个都设置,block的优先级高,即代理无效
 */

/**
 代理方法,用来计算item的高度
 */
@property (nonatomic, assign) id<CustomViewLayoutDelegate> delegate;

/**
 计算item高度的block,将item的高度与indexPath传递给外界
 */
@property (nonatomic, strong) CGFloat(^itemHeightBlock)(CGFloat itemHeight, NSIndexPath *indexPath);

#pragma mark ====== 构造方法 ======
+ (instancetype)customFallLayoutWithColumnCount:(float)columnCount;
- (instancetype)initWithColumCount:(float)columnCount;

@end

上面的文件主要是给外界提供一个接口,可以设置行数、行间距、列间距

实现的文件中,主要是找到UICollectionView中,最短的列数的最大Y值,把后面需要添加的item添加到这一列的下面,主要代码如下:

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    //根据indexPath获取item的attributes
    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
    //获取collectionView的宽度
    CGFloat collectionViewWidth = self.collectionView.frame.size.width;
    
    //item的宽度 = (collectionView的宽度 - 内边距与列间距) / 列数
    CGFloat itemWidth = (collectionViewWidth - self.sectionInset.left - self.sectionInset.right - (self.columnCount - 1) * self.columnSpacing) / self.columnCount;
    
    CGFloat itemHeight = 0;
    //获取item的高度,由外界计算得到
    if (self.itemHeightBlock) {
        itemHeight = self.itemHeightBlock(itemWidth, indexPath);
    } else {
        if ([self.delegate respondsToSelector:@selector(customFallLayout:itemHeightForWidth:atIndexPath:)]) {
            itemHeight = [self.delegate customFallLayout:self itemHeightForWidth:itemWidth atIndexPath:indexPath];
        }
    }
    
    //找出最短的那一列
    __block NSNumber *minIndex = @0;
    [self.maxYDic enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSNumber *obj, BOOL *stop) {
        if ([self.maxYDic[minIndex] floatValue] > obj.floatValue) {
            minIndex = key;
        }
    }];
    
    //根据最短列的列数计算item的x值
    CGFloat itemX = self.sectionInset.left + (self.columnSpacing + itemWidth) * minIndex.integerValue;
    
    //item的y值 = 最短列的最大y值 + 行间距
    CGFloat itemY = [self.maxYDic[minIndex] floatValue] + self.rowSpacing;
    
    //设置attributes的frame
    attributes.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight);
    
    //更新字典中的最大y值
    self.maxYDic[minIndex] = @(CGRectGetMaxY(attributes.frame));
    
    return attributes;
}

具体实现请看demo,
demo下载地址

相关文章:

  • 666!中国企业凭人脸识别勇夺“金牌”
  • CentOS7.2安装配置nginx+flask+python+uwsgi运行环境
  • 快速理解Linux内核态与用户态
  • python3 写一个简单的websocket程序(转)
  • 自测之Lesson16:并发通信
  • 软工作业PSP与单元测试训练
  • ElasticSearch入门及核心概念介绍
  • 软件工程第二周阅读作业
  • 前台vue的使用简单小结
  • SSRF(服务端请求伪造)
  • ubuntu下unzip解压zip文件中文乱码问题
  • 菜鸟网络与顺丰达成和解 确保数据安全进行合作
  • Android系统启动流程 -- android
  • Exchange 2016 CU9 已发布
  • js上传文件带进度条
  • [Vue CLI 3] 配置解析之 css.extract
  • 【159天】尚学堂高琪Java300集视频精华笔记(128)
  • CSS 三角实现
  • C学习-枚举(九)
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • Essential Studio for ASP.NET Web Forms 2017 v2,新增自定义树形网格工具栏
  • JS笔记四:作用域、变量(函数)提升
  • mysql常用命令汇总
  • Python - 闭包Closure
  • python docx文档转html页面
  • Python连接Oracle
  • Quartz初级教程
  • React系列之 Redux 架构模式
  • VirtualBox 安装过程中出现 Running VMs found 错误的解决过程
  • 对超线程几个不同角度的解释
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 深度学习在携程攻略社区的应用
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 项目实战-Api的解决方案
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性
  • mysql面试题分组并合并列
  • Prometheus VS InfluxDB
  • ​用户画像从0到100的构建思路
  • #快捷键# 大学四年我常用的软件快捷键大全,教你成为电脑高手!!
  • #微信小程序(布局、渲染层基础知识)
  • (23)Linux的软硬连接
  • (c语言)strcpy函数用法
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (十二)devops持续集成开发——jenkins的全局工具配置之sonar qube环境安装及配置
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .form文件_一篇文章学会文件上传
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • .NET Core 版本不支持的问题
  • .NET DataGridView数据绑定说明
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • /deep/和 >>>以及 ::v-deep 三者的区别
  • @serverendpoint注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • @WebService和@WebMethod注解的用法
  • [ 蓝桥杯Web真题 ]-布局切换