自定义UICollectionViewLayout—实现瀑布流效果
2016-01-05 21:04
501 查看
最终效果:
用到的第三方框架:
1.自定义UICollectionViewLayout实现瀑布流布局效果
2.控制器如何使用?
4.cell上用到的模型
用到的第三方框架:
1.自定义UICollectionViewLayout实现瀑布流布局效果
// // WaterflowLayout.h // 0104-瀑布流 #import <UIKit/UIKit.h> @class WaterflowLayout; @protocol WaterflowLayoutDelegate <NSObject> - (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<WaterflowLayoutDelegate> delegate; @end
// // WaterflowLayout.m // 0104-瀑布流 #import "WaterflowLayout.h" @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.columnsCount; i++) { NSString *column = [NSString stringWithFormat:@"%d", i]; self.maxYDict[column] = @(self.sectionInset.top); } // 2.计算所有cell的属性 [self.attrsArray removeAllObjects]; NSInteger count = [self.collectionView numberOfItemsInSection:0]; for (int i = 0; i<count; i++) { UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]]; [self.attrsArray addObject:attrs]; } } /** * 返回所有的尺寸 */ - (CGSize)collectionViewContentSize { __block NSString *maxColumn = @"0"; [self.maxYDict enumerateKeysAndObjectsUsingBlock:^(NSString *column, NSNumber *maxY, BOOL *stop) { if ([maxY floatValue] > [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
2.控制器如何使用?
// // ViewController.m // 0104-瀑布流 #import "ViewController.h" #import "WaterflowLayout.h" #import "ShopCell.h" #import "MJExtension.h" #import "Shop.h" #import "MJRefresh.h" @interface ViewController ()<UICollectionViewDataSource,UICollectionViewDelegate,WaterflowLayoutDelegate> @property(nonatomic,weak)UICollectionView *collectionView; @property(nonatomic,strong)NSMutableArray *shops; @end @implementation ViewController static NSString *const ID = @"shop"; - (NSMutableArray *)shops { if (_shops == nil) { self.shops = [NSMutableArray array]; //2.加载1.plist创建模型 NSArray *shopArray = [Shop objectArrayWithFilename:@"1.plist"]; [self.shops addObjectsFromArray:shopArray]; } return _shops; } - (void)viewDidLoad { [super viewDidLoad]; //1.创建UICollectionView [self createCollectionView]; //2.添加一个上来刷新尾部控件(MJRefresh) [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]; }); } /** * 创建UICollectionView */ - (void)createCollectionView { WaterflowLayout *layout = [[WaterflowLayout alloc] init]; layout.delegate = self; // layout.sectionInset = UIEdgeInsetsMake(100, 20, 40, 30); // layout.columnMargin = 20; // layout.rowMargin = 30; // layout.columnsCount = 4; UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; collectionView.delegate = self; collectionView.dataSource = self; [collectionView registerNib:[UINib nibWithNibName:@"ShopCell" bundle:nil] forCellWithReuseIdentifier:ID]; [self.view addSubview:collectionView]; self.collectionView = collectionView; } #pragma mark - UICollectionViewDataSource /** * 每组有多少个cell */ - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return self.shops.count; } /** * 返回cell */ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { ShopCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath]; cell.shop = self.shops[indexPath.item]; return cell; } #pragma mark - UICollectionViewDelegate - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"点击了第%ld个cell",(long)indexPath.item); } #pragma mark - WaterflowLayoutDelegat - (CGFloat)waterflowLayout:(WaterflowLayout *)waterflowLayout heightForWidth:(CGFloat)width atIndexPath:(NSIndexPath *)indexPath { Shop *shop = self.shops[indexPath.item]; return shop.h / shop.w * width; } @end3. 自定义的UICollectionViewCell
// // ShopCell.h // 0104-瀑布流 #import <UIKit/UIKit.h> @class Shop; @interface ShopCell : UICollectionViewCell @property(nonatomic,strong)Shop *shop; @end
// // ShopCell.m // 0104-瀑布流 #import "ShopCell.h" #import "Shop.h" #import "UIImageView+WebCache.h" @interface ShopCell() @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property (weak, nonatomic) IBOutlet UILabel *priceLabel; @end @implementation ShopCell /* iOS9 HTTP 不能正常使用的解决办法: 1.在Info.plist中添加NSAppTransportSecurity类型Dictionary。 2.在NSAppTransportSecurity下添加NSAllowsArbitraryLoads类型Boolean,值设为YES */ - (void)setShop:(Shop *)shop { _shop = shop; // 1.图片 [self.imageView sd_setImageWithURL:[NSURL URLWithString:shop.img] placeholderImage:[UIImage imageNamed:@"loading"]]; // 2.价格 self.priceLabel.text = shop.price; } - (void)awakeFromNib { // Initialization code } @end
4.cell上用到的模型
// // Shop.h #import <UIKit/UIKit.h> @interface Shop : NSObject @property (nonatomic, assign) CGFloat w; @property (nonatomic, assign) CGFloat h; @property (nonatomic, copy) NSString *img; @property (nonatomic, copy) NSString *price; @end
// // shop.m #import "Shop.h" @implementation Shop @end5.1.plist数据结构,实际开发中应该是去服务器获取数据
相关文章推荐
- day2-UI布局
- UIImage与UIbutton相关
- UI期的基础类 UIView 基本运行顺序
- LiberOffice install office productivity suite -- Chinese_simpl
- 蓝懿IOS学习UIScrollView/UIPageControl
- Builder模式(建造者模式)
- jQquery选取元素
- CodeForces 441A Valera and Antique Items
- IOS模态视图 (UI页面切换)
- easyui combobox级联(转载)
- iOS开发学习之UI篇3、UILabel
- leetcode第一刷_Unique Paths
- 优化UITableViewCell高度计算的那些事 附源码
- (转载)iOS UILabel自定义行间距时获取高度
- IOS(UI)_UIButton(按钮)和UIImageView(图片按钮)
- iOS开发学习之UI篇 1、UIView
- IOS(UI)_UILabel(标签)
- UE 无法初始化FTP组件
- 有value时,li元素序列号就是value值,没有value,则会递增
- 关于百度 UEditor的使用