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中瀑布流布局详解 的相关文章

随机推荐

  • 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 其实说到底瀑布流也就是