/** * 瀑布流Demo的主要代码,若想看完整的代码请到下面链接去下载 * * 链接: https://pan.baidu.com/s/1slByAHB 密码: r3q6 */ #import <UIKit/UIKit.h> @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @end
#import "AppDelegate.h" #import "RootViewController.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.window.backgroundColor = [UIColor whiteColor]; self.window.rootViewController = [[RootViewController alloc] init]; [self.window makeKeyAndVisible]; return YES; } @end
#import <UIKit/UIKit.h> @interface RootViewController : UIViewController @end
#import "RootViewController.h" #import "LFWaterfallLayout.h" #import "XMGShop.h" #import "MJExtension.h" #import "MJRefresh.h" #import "XMGShopCell.h" @interface RootViewController ()<UICollectionViewDataSource,LFWaterfallLayoutDelegate> @property (nonatomic , strong) UICollectionView *collectionView; /** * 所有商品数据 */ @property (nonatomic , strong) NSMutableArray *shops; @end @implementation RootViewController static NSString *const identifier = @"waterfall"; - (NSMutableArray *)shops{ if (!_shops) { _shops = [NSMutableArray array]; } return _shops; } - (void)viewDidLoad { [super viewDidLoad]; [self setupLayout]; [self setupRefresh]; } - (void)setupRefresh{ self.collectionView.header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewShops)]; [self.collectionView.header beginRefreshing]; self.collectionView.footer = [MJRefreshAutoNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreShops)]; self.collectionView.footer.hidden = YES; } - (void)loadNewShops{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSArray *shops = [XMGShop objectArrayWithFilename:@"1.plist"]; NSLog(@"%@",shops); [self.shops removeAllObjects]; [self.shops addObjectsFromArray:shops]; // 刷新数据 [self.collectionView reloadData]; [self.collectionView.header endRefreshing]; }); } - (void)loadMoreShops{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSArray *shops = [XMGShop objectArrayWithFilename:@"1.plist"]; [self.shops addObjectsFromArray:shops]; // 刷新数据 [self.collectionView reloadData]; [self.collectionView.footer endRefreshing]; }); } - (void)setupLayout{ // 创建布局 LFWaterfallLayout *layout = [[LFWaterfallLayout alloc] init]; layout.delegate = self; // 创建collecView self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; self.collectionView.backgroundColor = [UIColor whiteColor]; self.collectionView.dataSource = self; [self.view addSubview:self.collectionView]; // 注册 [self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([XMGShopCell class]) bundle:nil] forCellWithReuseIdentifier:identifier]; } #pragma mark -- UICollectionViewDataSource -- - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ self.collectionView.footer.hidden = self.shops.count == 0; return self.shops.count; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ XMGShopCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath]; cell.shop = self.shops[indexPath.item]; return cell; } #pragma mark -- LFWaterfallLayoutDelegate -- - (CGFloat)waterflowLayout:(LFWaterfallLayout *)waterflowLayout heightForItemAtIndex:(NSUInteger)index itemWidth:(CGFloat)itemWidth{ XMGShop *shop = self.shops[index]; return itemWidth * shop.h / shop.w ; } //- (CGFloat)rowMarginInWaterflowLayout:(LFWaterfallLayout *)waterflowLayout{ // return 30; //} - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
#import <UIKit/UIKit.h> @class LFWaterfallLayout; @protocol LFWaterfallLayoutDelegate <NSObject> @required - (CGFloat)waterflowLayout:(LFWaterfallLayout *)waterflowLayout heightForItemAtIndex:(NSUInteger)index itemWidth:(CGFloat)itemWidth; @optional - (CGFloat)columnCountInWaterflowLayout:(LFWaterfallLayout *)waterflowLayout; - (CGFloat)columnMarginInWaterflowLayout:(LFWaterfallLayout *)waterflowLayout; - (CGFloat)rowMarginInWaterflowLayout:(LFWaterfallLayout *)waterflowLayout; - (UIEdgeInsets)edgeInsetsInWaterflowLayout:(LFWaterfallLayout *)waterflowLayout; @end @interface LFWaterfallLayout : UICollectionViewLayout @property (nonatomic , weak) id<LFWaterfallLayoutDelegate> delegate; @end
#import "LFWaterfallLayout.h" static const NSInteger LFDefaultColumnCount = 3;//默认的列数 static const CGFloat LFDefaultColumnMargin = 10;//每一列之间的间距 static const CGFloat LFDefaultRowMargin = 10;//每一行之间的间距 static const UIEdgeInsets LFDefaultEdgeInsets = {10,10,10,10};//边缘间距 @interface LFWaterfallLayout () /** * 存放所有cell的布局属性 */ @property (nonatomic , strong) NSMutableArray *attrsArray; /** * 存放所有列的当前高度 */ @property (nonatomic , strong) NSMutableArray *columnHeights; - (CGFloat)rowMargin; - (CGFloat)columnMargin; - (NSInteger)columnCount; - (UIEdgeInsets)endgeInsets; @end @implementation LFWaterfallLayout #pragma mark -- 数据处理 -- - (CGFloat)rowMargin{ if ([self.delegate respondsToSelector:@selector(rowMarginInWaterflowLayout:)]) { return [self.delegate rowMarginInWaterflowLayout:self]; }else{ return LFDefaultRowMargin; } } - (CGFloat)columnMargin{ if ([self.delegate respondsToSelector:@selector(columnMarginInWaterflowLayout:)]) { return [self.delegate columnMarginInWaterflowLayout:self]; }else{ return LFDefaultColumnMargin; } } - (NSInteger)columnCount{ if ([self.delegate respondsToSelector:@selector(columnCountInWaterflowLayout:)]) { return [self.delegate columnCountInWaterflowLayout:self]; }else{ return LFDefaultColumnCount; } } - (UIEdgeInsets)endgeInsets{ if ([self.delegate respondsToSelector:@selector(edgeInsetsInWaterflowLayout:)]) { return [self.delegate edgeInsetsInWaterflowLayout:self]; }else{ return LFDefaultEdgeInsets; } } - (NSMutableArray *)attrsArray{ if (!_attrsArray) { _attrsArray = [NSMutableArray array]; } return _attrsArray; } - (NSMutableArray *)columnHeights{ if (!_columnHeights) { _columnHeights = [NSMutableArray array]; } return _columnHeights; } /** * 初始化 */ - (void)prepareLayout{ [super prepareLayout]; // 清除以前计算的所有高度 [self.columnHeights removeAllObjects]; for (NSInteger i = 0; i < self.columnCount; i++) { [self.columnHeights addObject:@(self.endgeInsets.top)]; } // 清除之前所有的布局属性 [self.attrsArray removeAllObjects]; // 开始创建每一个cell对应的布局属性 NSInteger count = [self.collectionView numberOfItemsInSection:0]; for (NSInteger i = 0 ;i < count;i++) { // 创建位置 NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0]; // 获取indexPath位置对应cell的属性 UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath]; [self.attrsArray addObject:attributes]; } } /** * 决定cell的布局 */ - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{ return self.attrsArray; } /** * 返回indexPath位置cell对应的布局属性 */ - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{ // 创建布局属性 UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; //collectionView的宽度 CGFloat collectionViewWidth = self.collectionView.frame.size.width; // 找出高度最短的那一列 NSInteger shortestColumn = 0; // 找出最小高度 CGFloat minColumnHeight = [self.columnHeights[0] doubleValue]; for (NSInteger i = 1 ; i < self.columnCount; i++) { // 取出第i列的高度 CGFloat columnHeight = [self.columnHeights[i] doubleValue]; // 比较大小 if (minColumnHeight > columnHeight) { minColumnHeight = columnHeight; shortestColumn = i; } } // 宽度 CGFloat width = (collectionViewWidth - self.endgeInsets.left - self.endgeInsets.right - (self.columnCount - 1) *self.columnMargin) / self.columnCount; // x坐标 CGFloat x = self.endgeInsets.left + shortestColumn * (width + self.columnMargin); // y坐标 CGFloat y = minColumnHeight; if (y != self.endgeInsets.top) { y += self.rowMargin; } // 高度 CGFloat height = [self.delegate waterflowLayout:self heightForItemAtIndex:indexPath.item itemWidth:width]; //设置布局属性的frame attributes.frame = CGRectMake(x,y, width, height); // 更新高度 self.columnHeights[shortestColumn] = @(CGRectGetMaxY(attributes.frame)); return attributes; } - (CGSize)collectionViewContentSize{ // 找出最大高度 CGFloat maxColumnHeight = [self.columnHeights[0] doubleValue]; for (NSInteger i = 1 ; i < self.columnCount; i++) { // 取出第i列的高度 CGFloat columnHeight = [self.columnHeights[i] doubleValue]; // 比较大小 if (maxColumnHeight < columnHeight) { maxColumnHeight = columnHeight; } } return CGSizeMake(0, maxColumnHeight + self.endgeInsets.bottom); } @end
#import <UIKit/UIKit.h> @interface XMGShop : NSObject @property (nonatomic, assign) CGFloat w; @property (nonatomic, assign) CGFloat h; @property (nonatomic, copy) NSString *img; @property (nonatomic, copy) NSString *price; @end
#import "XMGShop.h" @implementation XMGShop @end
#import <UIKit/UIKit.h> @class XMGShop; @interface XMGShopCell : UICollectionViewCell @property (nonatomic, strong) XMGShop *shop; @end
#import "XMGShopCell.h" #import "XMGShop.h" #import "UIImageView+WebCache.h" @interface XMGShopCell() @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property (weak, nonatomic) IBOutlet UILabel *priceLabel; @end @implementation XMGShopCell - (void)setShop:(XMGShop *)shop { _shop = shop; // 1.图片 [self.imageView sd_setImageWithURL:[NSURL URLWithString:shop.img] placeholderImage:[UIImage imageNamed:@"loading"]]; // 2.价格 self.priceLabel.text = shop.price; } @end