iOS中瀑布流布局详解

2023-05-16

前段时间在逛淘宝的时候发现淘宝的商品界面的布局是瀑布流(我记得明明之前不是瀑布流的😑)。刚好手上活忙完了,写了一个瀑布流的布局,简单的封装了下,以便日后使用😏。其实说到底瀑布流也就是UICollectionView做的,只是修改了CollectionView的流式布局(FlowLayout),以后要用就直接把自定义的FlowLayout拿过来用就行了。

 

 

瀑布流

1.要有瀑布流首先得有colletionView,所以先在viewController中把我们的colletionView弄出来。因为没有做网络请求,所以现在我模拟了一份数据,都是在plist里面装着在呢。

 

plist数据

 

相关图片

这里强调一下,因为我是直接用sb的方式加载的,所以代理啊,数据源啊都不用写了,包括后面自定义cell中的那些控件都是直接拉线连的。那这里我们就直接上数据源方法

#pragma mark 数据源 

-(NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
    return self.dataArr.count;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    CYWCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
    cell.model = self.dataArr[indexPath.item];
    return cell;
}

用懒加载的方式去加载plist中的数据

@interface ViewController ()
//懒加载之后的数据数组
@property (nonatomic,strong) NSMutableArray *dataArr;
@end
#pragma mark 懒加载
-(NSMutableArray *)dataArr{
    if (_dataArr == nil) {
        NSArray *arr = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"1.plist" ofType:nil]];  
        NSMutableArray *arrM = [NSMutableArray arrayWithCapacity:arr.count];
        for (NSDictionary *dict in arr) {
            CYWModel *model = [CYWModel modelWithDict:dict];
            [arrM addObject:model];
        }
        _dataArr = arrM;
    }
    return _dataArr;
}

用来接受数据的模型

记得.h中要引入UIKit框架,不然CGFloat是敲不出来的

#import <UIKit/UIKit.h>

@interface CYWModel : NSObject
//高
@property (nonatomic,assign) CGFloat height;
//宽
@property (nonatomic,assign) CGFloat width;
//图片
@property (nonatomic,copy) NSString *icon;
//价格
@property (nonatomic,copy) NSString *price;
+(instancetype) modelWithDict:(NSDictionary *)dict;

@end

.m中最好实现下orUndefinedKey:方法,怕万一通过KVC没找到对应的key时候崩掉

#import "CYWModel.h"
@implementation CYWModel
+(instancetype)modelWithDict:(NSDictionary *)dict{
    id obj = [[self  alloc] init];
    [obj setValuesForKeysWithDictionary:dict];
    return obj;
}
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
    NSLog(@"%@ --- %@",value,key);
}
@end

接下来自定义的cell中引入模型属性,重写set方法就好了。

@interface CYWCell ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UILabel *priceLabel;
@end
@implementation CYWCell
-(void)setModel:(CYWModel *)model{
    _model = model;
    self.imageView.image = [UIImage imageNamed:model.icon];
    self.priceLabel.text = model.price;
}

接下来在模拟器中如果能运行出如下图的样子就行了

 

示例

那么醉关键了位置就是接下来自定义我们的UICollectionViewFlowLayout

这是.h中留出来给控制器赋值的属性,到时候你还可以自己添加你需要的属性。

#import <UIKit/UIKit.h>

@interface CYWWaterFallLayout : UICollectionViewFlowLayout

//列数
@property (nonatomic,assign) NSInteger colCount;

//数据
@property (nonatomic,strong) NSArray *dataList;

@end

这是.m文件,关键的地方的注释我也写上去了。

另外在插句嘴,其实瀑布流最主要就是限宽不限高去计算;另外,你以后在需要瀑布流布局的时候一定要记得找后台的哥们把图片的真实尺寸传过来,因为你需要计算长宽比。#######

#import "CYWWaterFallLayout.h"
#import "CYWModel.h"


@interface CYWWaterFallLayout ()

//用来返回布局的数组
@property (nonatomic,strong) NSMutableArray *dataArr;
// 用来保存每一列item当前的总高

@property (nonatomic, strong) NSMutableArray *eachColumnMaxHight;

@end

@implementation CYWWaterFallLayout


/*
 * 准备开始布局 调用collectionView的 relodata方法也会调用这个方法 
 * 所以在这个方法里面自定义瀑布流的布局
 */
-(void)prepareLayout{
//    获取collectionView中第0组的item个数
    NSInteger itemNum= [self.collectionView numberOfItemsInSection:0];
    
    for (NSInteger i = 0; i < itemNum; i++) {
        
        NSIndexPath *indexpath = [NSIndexPath indexPathForItem:i inSection:0];
//        布局
        UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexpath];
        
//        总宽
        CGFloat contentW = self.collectionView.bounds.size.width - self.sectionInset.left - self.sectionInset.right;
//        item宽
        CGFloat itemW = (contentW - (self.colCount - 1) * self.minimumInteritemSpacing) / self.colCount;
//        获取item高
        CYWModel *model = self.dataList[i];
        CGFloat itemH = itemW * (model.height /model.width);
        
//        itemX
        NSInteger colNum = i % self.colCount;
        CGFloat itemX = self.sectionInset.left + (itemW + self.minimumInteritemSpacing) * colNum;
        
//        itemY
        CGFloat itemY = [self.eachColumnMaxHight[colNum] floatValue];
        
        attr.frame = CGRectMake(itemX, itemY, itemW, itemH);
//        重新给数组中的最高y赋值
        self.eachColumnMaxHight[colNum] = @(itemY + itemH + self.minimumLineSpacing);
        
        [self.dataArr addObject:attr];
        
    }
    
}

//返回collectioView的滚动范围
-(CGSize)collectionViewContentSize{
    NSInteger maxCol = [self calculateMaxHeightCol];
    return CGSizeMake(0, [self.eachColumnMaxHight[maxCol] floatValue] - self.minimumLineSpacing);
}

-(NSInteger)calculateMaxHeightCol{
    NSInteger maxCol = 0;
    CGFloat maxHeight = 0;
    
    for (NSInteger i = 0; i < self.colCount; i++) {
        if (maxHeight < [self.eachColumnMaxHight[i] floatValue]) {
            maxHeight = [self.eachColumnMaxHight[i] floatValue];
            maxCol = i;
        }
    }
    return maxCol;
}

//这个方法中可以返回collectionView上所用item的索引,rect
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
    return self.dataArr;
}


#pragma mark 懒加载
-(NSMutableArray *)dataArr{
    if (_dataArr == nil) {
        _dataArr = [NSMutableArray array];
    }
    return _dataArr;
}


- (NSMutableArray *)eachColumnMaxHight {
    if (_eachColumnMaxHight == nil) {
        // 初始化可变数组
        _eachColumnMaxHight = [NSMutableArray arrayWithCapacity:self.colCount];
        // 给数组中的中赋值初始值
        for (NSInteger i = 0; i < self.colCount; i++) {
            // 让每一列当前的高度为一个组的顶部间距
            _eachColumnMaxHight[i] = @(self.sectionInset.top);
        }
    }
    return _eachColumnMaxHight;
}
@end

最后,我把这个demo放在了GitHub上,有兴趣的可以看看哈https://github.com/YWDrenched/C1

 

13人点赞

 

iOSer

 



作者:YW_Drenched
链接:https://www.jianshu.com/p/a5401b21391e
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS中瀑布流布局详解 的相关文章

  • 将类型传递给通用 Swift 扩展,或者理想情况下推断它

    说你有 class Fancy UIView 你想找到所有兄弟姐妹Fancy意见 没问题 https stackoverflow com q 37232743 294884 for v UIView in superview subview
  • 无法以编程方式快速设置 NSLayoutConstraint 乘数...“无法分配给此表达式的结果

    我试图以编程方式快速设置乘法器的约束 当我设置该值时 它只会给我错误 无法分配给该表达式的结果 我用 IBOutlet 声明了 NSLayoutConstraint 然后设置乘数 就像我对另一个常量所做的那样 效果很好 但这个不会接受它 I
  • 有没有办法在 onclick 触发时禁用 iPad/iPhone 上的闪烁/闪烁?

    所以我有一个有 onclick 事件的区域 在常规浏览器上单击时 它不会显示任何视觉变化 但在 iPad iPhone 上单击时 它会闪烁 闪烁 有什么办法可以阻止它在 iPad iPhone 上执行此操作吗 这是一个与我正在做的类似的示例
  • 诊断和仪器均缺少“僵尸”选项

    运行 Xcode 4 0 2 Zombie 选项丢失 其他 SO 帖子建议找到它的两个地方 Product gt Run looks like this Product gt Profile looks like this 奇怪的是 我之前
  • iOS 无状态/无值进度条?

    我希望在 iOS 中获得无状态 无值的 UIProgressView 或其他类型的进度条 我尝试查找一些文档 但找不到与我的问题相关的任何内容 如果你们有任何建议 我很想听听 Thanks Shai iOS s UI进度视图 https d
  • IOS 应用程序提交导出合规性:Firebase

    我准备将我的应用程序提交到应用程序商店 经过一些研究后 我似乎仍然无法在我的应用程序中找到有关 firebase 的任何信息 Firebase 是否可以豁免 我只用它来进行分析和 Admob 那么 Firebase 是否使用加密 如果使用
  • Firebase queryOrderedbyChild 不返回 Null 值

    我有一个根据年龄搜索用户的查询 self ref child users queryOrdered byChild age queryStarting atValue 18 queryEnding atValue 25 observeSin
  • 将 Google 登录与两个目标结合使用

    我有一个问题一直无法解决 我到处都在寻找 我最近将 Google Sign in 添加到我的应用程序中 并且它在主目标上运行良好 但是 由于我使用多个目标来部署应用程序的辅助版本 因此无法将第二个包标识符添加到 GoogleService
  • UITableViewCell 上的自动布局问题

    我在使用自动布局时遇到问题xcode 5项目 我在内部使用带有导航控制器的普通视图控制器 我有一个MKMapView在上半部分和一个UITableView在下半部分 我在用storyboards 并配置了原型UITableViewCell
  • 将小箭头添加到 iPhone TableView 单元格中单元格的右侧

    这应该很简单 我有一个带有 TableView 的 iPhone 应用程序 如何将经典的小箭头添加到每个单元格的右侧 只需设置相应的附件类型的财产UITableViewCell cell accessoryType UITableViewC
  • 如果应用程序意外关闭,如何重新启动应用程序

    Skype 更新文本 http www iclarified com entry index php enid 21659包含下一个 如果意外关闭 应用程序会自动重新启动 如何通过 SDK 执行此操作 据我所知 某些类型的应用程序可以在后台
  • 如何通过 Google Sheets API 进行基本写作?

    在使用 Swift 学习 Google Sheets API 的过程中 我想将单个范围写入电子表格 调查iOS 快速入门指南 https developers google com sheets quickstart ios ver swi
  • 如何更改 MGLPolyline 的颜色?

    如何更改 MGLPolyline 的颜色 我曾经看过here https stackoverflow com questions 32024464 customize mglpolyline using mapbox但答案不起作用 我还尝试
  • CLGeocoder reverseGeocodeLocation 返回“kCLErrorDomain 错误 9”

    我正在根据本文开发具有反向地理编码功能的 iOS 应用程序 地理编码教程 http jonathanfield me jons blog clgeocoder example html 但是当我在模拟器上进行这样的测试时 我收到 kCLEr
  • 自定义 URL 方案不是 Outlook 中的链接 (iOS/Android)

    我们的应用程序可以使用自定义 URL 方案启动 例如myapp mainpage param 123 当它作为链接包含在网页中时 此功能有效 而且 在 iOS 上 它可以在平台附带的邮件客户端中运行 用户注册并安装该应用程序后 他会收到一封
  • 使用 AFNetworking 重置基本身份验证凭据

    我正在编写一个 REST 客户端 使用 AFNetworking 并且需要能够在应用程序的单个实例中触发新会话的创建 换句话说 我想 1 通过服务器进行身份验证2 进行一些 REST 调用3 模拟 注销 4 重新与服务器进行身份验证5 进行
  • SwiftUI 键盘工具栏有条件

    不确定这是否是一个错误或者我是否做错了什么 但如果我使用 toolbar ToolbarItemGroup placement navigationBarLeading if isFocused zipCode Text Test 当等于
  • Phonegap - navigator.app.backHistory() 不适用于 HTML 后退按钮

    在我的应用程序中 我使用phonegap 2 6 对于后退按钮 我使用以下函数 document addEventListener backbutton onBackKeyDown false function onBackKeyDown
  • 图像高斯模糊 - iOS 8

    我有一个移动的背景图像 我想模糊它的底部 我would只用 Photoshop 就能做到 但由于图像会移动 效果不太好 这就是我的意思 看图片底部 基本上就像底座对 iPhone 的影响一样 我使用的是 iOS 8 但不是 Swift 我根
  • iOS7 XIB 问题。顶部和底部的空白

    我有一个正在设置 ImageView 的视图 自动布局已选中 预览中看起来不错 但当应用程序实际在模拟器上运行时 仅在 iPhone 视网膜 4 英寸模拟器中 顶部和底部显示空白 3 5寸的看起来还不错 使用 iOS7 和 XCODE 5

随机推荐

  • Luogu 3642 [APIO 2016] 烟火表演

    传送门引例 xff08 上一道题 xff09 凸函数一开始的思路正解参考代码总结 传送门 引例 xff08 上一道题 xff09 凸函数 回忆我们上一道题是怎么做的 我们维护的东西的实质是一个 xff08 下 xff09 凸函数 由于我们的
  • Luogu 3631 [APIO 2011] 方格染色

    传送门思路参考代码细节 传送门 思路 很不错的一道题 xff0c 用到的东西不深 xff0c 但是要想到确实需要一定思维 一开始我想的是动态规划 xff0c 发现如果要设状态需要知道一个格子左边 xff0c 上边和左上边三个格子的状态 然后
  • Luogu 3632 [APIO 2011] 寻路

    传送门正解参考代码 传送门 正解 暴力连边跑最短路就好了 xff0c 只不过代码太长太难写啦 xff01 参考代码 span class hljs preprocessor include lt cstdio gt span span cl
  • Luogu 3634 [APIO 2012] 守卫

    传送门思路正解参考代码 传送门 思路 感觉自己越来越笨了 首先 xff0c 很明显这道题需要把没有看到忍者的区间给删去 xff0c 可以用前缀和 O n O n 处理 xff0c 然后对没有删去的地方重新标号 重新标号时 xff0c 需要对
  • Luogu 1552 [APIO 2012] 派遣

    传送门思路参考代码 传送门 思路 唉 xff0c 我太弱了 xff0c 什么都不会 xff0c 题读错了两次 xff0c 一开始读成了一个一般的背包 xff0c 然后读成了一个价值和花费相同的背包 xff0c 最后才发现原来是一个价值为 1
  • 贪玩 CF 之旅

    文章目录 CF 7D Palindrome Degree http codeforces com problemset problem 7 D 题解 CF 713C Sonya and Problem Wihtout a Legend ht
  • Luogu 3638 [APIO 2013] 机器人

    传送门思路正解参考代码关于 SPFA 传送门 思路 n n 这么小 会不会是搜索题 稍有经验的我直接否定了这个结论 仔细读题并分析样例 发现原来一个位置可以有多个机器人 且机器人行走的时候无视其它机器人 那这个就是一张图啊 可以将这张图预处
  • Luogu 3647 [APIO 2014] 连珠线

    传送门思路参考代码 传送门 思路 唉 xff0c 我太弱了 xff0c 又看错题了 题目中说一个新的珠子和一个已经添加的珠子连接起来 xff0c 我没有看到 xff0c 然后就凉了 立个 flag xff1a 已经连续看错五题了 xff0c
  • 【转】mingw64的安装方法

    转自 xff1a http write blog csdn net postlist mingw64的安装方法 1 下载ming w64 http sourceforge net projects mingw w64 files or x8
  • Luogu 3645 [APIO 2015] 雅加达的摩天楼

    传送门思路正解参考代码Update 传送门 思路 唉 xff0c 我太弱了 xff0c 我都看出来要分块了 xff0c 就是做不来 不过终于把题读对了 先来看子任务三怎么做 显然可以有一个 O m 2 O m 2
  • Luogu 3644 [APIO 2015] 八邻旁之桥

    传送门思路当 k 61 2 时参考代码 传送门 思路 唉 xff0c 我太弱了 xff0c 什么都不会 xff0c 题也做不来 很明显这道题先要把不过河的人排除了 xff0c 剩下的都是要过河的 当 k 61 1 k 61 1 时 xff0
  • Luogu 3646 [APIO 2015] 巴厘岛的雕塑

    传送门总结 APIO 2015思路参考代码总结 传送门 总结 APIO 2015 争取今天做完一套 QAQ T1 我最多之能想到从高位向低位做 xff0c 然后就完全不会了 xff1b T2 我想到了分情况讨论 xff0c 但是没有建图成功
  • UOJ 2016 [APIO 2016] Gap

    传送门思路参考代码交互题 交互题大致形式Windows 平台下 xff08 Dev C 43 43 xff09 Ubuntu 平台下 传送门 思路 唉 xff0c 我太弱了 xff0c 什么都不会 xff0c 题也做不来 这道题简直就是利用
  • CF 940F Machine Learning

    传送门题目大意思路参考代码Remarks 传送门 题目大意 给你一个数组 a 1 n n 10 5 a 1 n
  • CF 976D Degree Set

    传送门题目大意思路参考代码总结 传送门 题目大意 给你一个长度为 n n 的正整数序列 d 1 d 2 d n d1 d2 dn xff08 d 1 lt d 2 lt lt d n
  • Luogu 3778 [APIO 2017] 商旅

    传送门思路参考代码 传送门 思路 唉 xff0c 我太弱了 xff0c 什么都不会 看到这道题就想到了二分答案找负环 xff0c 但是怎么做呢 xff1f 完全不会 唉 xff0c 我太弱啦 xff01 先注意题目中说可以重复经过点和边 x
  • CF 963E Circles of Waiting

    传送门题目大意思路参考代码 传送门 题目大意 在平面直角坐标系上 xff0c 有一个神奇的点 xff0c 一开始在 0 0 0 0 每秒钟这个点都会随机移动 xff1a 如果它在 x y
  • CF 976F Minimal k-covering

    传送门题目大意 输入格式输出格式 思路参考代码 传送门 题目大意 给你一张二分图 G 61 U V E G 61 U V
  • CF 963A Alternating Sum

    传送门思路参考代码 传送门 思路 唉 xff0c 我太弱了 xff0c 什么都不会 xff0c 好不容易做得来一道题 xff0c 还是 A 题 xff08 所以不要瞧不起 A 题 xff09 xff0c 结果还写错了 xff08 不知道为什
  • iOS中瀑布流布局详解

    前段时间在逛淘宝的时候发现淘宝的商品界面的布局是瀑布流 我记得明明之前不是瀑布流的 x1f611 刚好手上活忙完了 xff0c 写了一个瀑布流的布局 xff0c 简单的封装了下 xff0c 以便日后使用 x1f60f 其实说到底瀑布流也就是