博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ios 瀑布流
阅读量:6186 次
发布时间:2019-06-21

本文共 5969 字,大约阅读时间需要 19 分钟。

瀑布流,也被称为瀑布流布局。

行的一种,视觉表现为參差不齐的多栏布局,随着页面滚动栏向下滚动,这样的布局还会不断载入并附加至当前尾部。

说明(1)瀑布流每个的宽度是一样的,都是高度不一样(2)补齐算法,哪里比較短就补哪里,不是简单的从左到右排(两列之间的差距越来越大)。

在ios中眼下比較好的实现方式有2种。1.仿照UITableView思路自己定义ScrollView 2.使用UICollectionView,自己定义UICollectionViewLayout实现.

使用UICollectionView,自己定义UICollectionViewLayout实现

ViewController.m
#import "ViewController.h"#import "WaterflowLayout.h"@interface ViewController () 
@property (nonatomic, weak) UICollectionView *collectionView;@property (nonatomic, strong) NSMutableArray *shops;@end@implementation ViewController- (NSMutableArray *)shops{ if (_shops == nil) { self.shops = [NSMutableArray array]; } return _shops;}static NSString *const ID = @"shop";- (void)viewDidLoad { [super viewDidLoad]; // 1.初始化数据 NSArray *shopArray = [Shop objectArrayWithFilename:@"1.plist"]; [self.shops addObjectsFromArray:shopArray]; WaterflowLayout *layout = [[WaterflowLayout alloc] init]; layout.delegate = self;// layout.sectionInset = UIEdgeInsetsMake(100, 20, 40, 30);// layout.columnMargin = 20;// layout.rowMargin = 30;// layout.columnsCount = 4; // 2.创建UICollectionView UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; collectionView.backgroundColor = [UIColor whiteColor]; collectionView.dataSource = self; collectionView.delegate = self; [collectionView registerNib:[UINib nibWithNibName:@"ShopCell" bundle:nil] forCellWithReuseIdentifier:ID]; [self.view addSubview:collectionView]; self.collectionView = collectionView; // 3.添加刷新控件 [self.collectionView addFooterWithTarget:self action:@selector(loadMoreShops)];}- (void)loadMoreShops{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSArray *shopArray = [Shop objectArrayWithFilename:@"1.plist"]; [self.shops addObjectsFromArray:shopArray]; [self.collectionView reloadData]; [self.collectionView footerEndRefreshing]; });}#pragma mark -
- (CGFloat)waterflowLayout:(WaterflowLayout *)waterflowLayout heightForWidth:(CGFloat)width atIndexPath:(NSIndexPath *)indexPath{ Shop *shop = self.shops[indexPath.item]; return shop.h / shop.w * width;}#pragma mark -
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ return self.shops.count;}- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ ShopCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath]; cell.shop = self.shops[indexPath.item]; return cell;}@end
WaterflowLayout.h
#import 
@class WaterflowLayout;@protocol WaterflowLayoutDelegate
- (CGFloat)waterflowLayout:(WaterflowLayout *)waterflowLayout heightForWidth:(CGFloat)width atIndexPath:(NSIndexPath *)indexPath;@end@interface WaterflowLayout : UICollectionViewLayout@property (nonatomic, assign) UIEdgeInsets sectionInset;/** 每一列之间的间距 */@property (nonatomic, assign) CGFloat columnMargin;/** 每一行之间的间距 */@property (nonatomic, assign) CGFloat rowMargin;/** 显示多少列 */@property (nonatomic, assign) int columnsCount;@property (nonatomic, weak) id
delegate;@end
WaterflowLayout.m
#import "WaterflowLayout.h"//static const CGFloat ColumnMargin = 10;//static const CGFloat RowMargin = ColumnMargin;@interface WaterflowLayout();/** 这个字典用来存储每一列最大的Y值(每一列的高度) */@property (nonatomic, strong) NSMutableDictionary *maxYDict;/** 存放全部的布局属性 */@property (nonatomic, strong) NSMutableArray *attrsArray;@end@implementation WaterflowLayout- (NSMutableDictionary *)maxYDict{    if (!_maxYDict) {        self.maxYDict = [[NSMutableDictionary alloc] init];    }    return _maxYDict;}- (NSMutableArray *)attrsArray{    if (!_attrsArray) {        self.attrsArray = [[NSMutableArray alloc] init];    }    return _attrsArray;}- (instancetype)init{    if (self = [super init]) {        self.columnMargin = 10;        self.rowMargin = 10;        self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);        self.columnsCount = 3;    }    return self;}- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{    return YES;}/** *  每次布局之前的准备 */- (void)prepareLayout{    [super prepareLayout];        // 1.清空最大的Y值    for (int i = 0; i
[self.maxYDict[maxColumn] floatValue]) { maxColumn = column; } }]; return CGSizeMake(0, [self.maxYDict[maxColumn] floatValue] + self.sectionInset.bottom);}/** * 返回indexPath这个位置Item的布局属性 */- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{ // 如果最短的那一列的第0列 __block NSString *minColumn = @"0"; // 找出最短的那一列 [self.maxYDict enumerateKeysAndObjectsUsingBlock:^(NSString *column, NSNumber *maxY, BOOL *stop) { if ([maxY floatValue] < [self.maxYDict[minColumn] floatValue]) { minColumn = column; } }]; // 计算尺寸 CGFloat width = (self.collectionView.frame.size.width - self.sectionInset.left - self.sectionInset.right - (self.columnsCount - 1) * self.columnMargin)/self.columnsCount; CGFloat height = [self.delegate waterflowLayout:self heightForWidth:width atIndexPath:indexPath]; // 计算位置 CGFloat x = self.sectionInset.left + (width + self.columnMargin) * [minColumn intValue]; CGFloat y = [self.maxYDict[minColumn] floatValue] + self.rowMargin; // 更新这一列的最大Y值 self.maxYDict[minColumn] = @(y + height); // 创建属性 UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; attrs.frame = CGRectMake(x, y, width, height); return attrs;}/** * 返回rect范围内的布局属性 */- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{ return self.attrsArray;}@end

版权声明:本文博主原创文章。博客,未经同意不得转载。

你可能感兴趣的文章
linux基础命令(更新中......)
查看>>
Eclipse.ini配置文件 各参数的意义
查看>>
Rabbitmq 相关介绍之单机普通模式集群配置
查看>>
win10 64位 ieda 绿色版免安装
查看>>
微软私有云最佳工作模式
查看>>
Ceph - howto, rbd, lvm, cluster
查看>>
virtualbox kernel panic - not syncing
查看>>
每日一shell(十一)mysql强制自动修改密码
查看>>
iptables基础应用
查看>>
升级python之后不能使用yum?
查看>>
如何测试Ajax动态分页列表的最大可翻页数?
查看>>
linux 2.6x内核升级
查看>>
完整的TCP/IP 7层
查看>>
HBase 源码-Run Shell
查看>>
Excel导入
查看>>
golang中时间戳格式化
查看>>
RDIFramework.NET开发实例━表约束条件权限的使用-Web
查看>>
Linux01-企业核心技术之逻辑卷LVM深入解析和实战36
查看>>
linux shell变量获取执行结果
查看>>
怎样理解Servlet的单实例多线程
查看>>