【代码笔记】自定义布局实现瀑布流
利用collectionView实现瀑布流的效果,
文件目录如下
动画效果图如下:
1 //ViewController文件 2 3 #import "ViewController.h" 4 #import "LYWaterFlowLayout.h" 5 #import "LYWaterCell.h" 6 #import "LYShopModel.h" 7 8 @interface ViewController ()<UICollectionViewDataSource> 9 @property(nonatomic,strong)NSArray *shops; 10 11 12 @end 13 14 @implementation ViewController 15 static NSString *ID = @"water"; 16 17 - (NSArray *)shops{ 18 19 if (_shops == nil) { 20 // 1.读取文件 21 NSString *path = [[NSBundle mainBundle ]pathForResource:@"1.plist" ofType:nil]; 22 NSArray *dictArray = [NSArray arrayWithContentsOfFile:path]; 23 // 2.字典转模型 24 NSMutableArray *tempArray = [NSMutableArray array]; 25 for (NSDictionary *dict in dictArray) { 26 LYShopModel *shop = [LYShopModel shopWithDict:dict]; 27 [tempArray addObject:shop]; 28 29 } 30 _shops = tempArray; 31 32 33 34 } 35 return _shops; 36 } 37 38 - (void)viewDidLoad { 39 [super viewDidLoad]; 40 // Do any additional setup after loading the view, typically from a nib. 41 // 0.自定义布局 42 LYWaterFlowLayout *waterFlowLayout = [[LYWaterFlowLayout alloc]init]; 43 // 0.1.传递外界数组到内部 44 waterFlowLayout.shops = self.shops; 45 46 // 1.创建collectionView 47 UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) collectionViewLayout:waterFlowLayout]; 48 // 2.设置数据源 49 collectionView.dataSource = self; 50 //// 3.设置代理 51 // collectionView.delegate = self; 52 53 54 // 3.添加 55 [self.view addSubview:collectionView]; 56 // 4.注册cell 57 [collectionView registerNib:[UINib nibWithNibName:@"LYWaterCell" bundle:nil] forCellWithReuseIdentifier:ID]; 58 59 60 } 61 62 - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{ 63 64 return 1; 65 66 } 67 68 - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ 69 70 return self.shops.count; 71 } 72 73 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ 74 75 76 // 1.创建cell 77 78 LYWaterCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath]; 79 // 2.赋值 80 // 81 // cell.backgroundColor = [UIColor redColor]; 82 // 2.1获取模型 83 LYShopModel *shop = self.shops[indexPath.item]; 84 cell.shop = shop; 85 86 cell.indexPath=indexPath; 87 // 3.返回cell 88 return cell; 89 90 91 } 92 93 @end
1 //LYWaterCell文件 2 #import <UIKit/UIKit.h> 3 @class LYShopModel; 4 5 @interface LYWaterCell : UICollectionViewCell 6 @property(nonatomic,strong)LYShopModel *shop; 7 8 @property(nonatomic,strong)NSIndexPath *indexPath; 9 10 @end 11 12 13 14 15 16 #import "LYWaterCell.h" 17 #import "LYShopModel.h" 18 19 @interface LYWaterCell() 20 21 @property (weak, nonatomic) IBOutlet UIImageView *iconView; 22 @property (weak, nonatomic) IBOutlet UILabel *priceLabel; 23 24 @end 25 @implementation LYWaterCell 26 - (void)setShop:(LYShopModel *)shop{ 27 28 _shop = shop; 29 30 self.iconView.image = [UIImage imageNamed:shop.icon]; 31 //self.priceLabel.text = shop.price; 32 33 } 34 -(void)setIndexPath:(NSIndexPath *)indexPath{ 35 36 _indexPath = indexPath; 37 self.priceLabel.text = self.shop.price; 38 39 } 40 41 @end
1 //LYWaterFlowLayout文件 2 #import <UIKit/UIKit.h> 3 4 @interface LYWaterFlowLayout : UICollectionViewFlowLayout 5 6 7 8 @property(nonatomic,strong)NSArray *shops; 9 10 11 @end 12 13 14 15 16 17 int const column = 3; 18 #import "LYWaterFlowLayout.h" 19 #import "LYShopModel.h" 20 21 @interface LYWaterFlowLayout() 22 23 @property(nonatomic,strong)NSMutableArray *maxYs; 24 @end 25 26 @implementation LYWaterFlowLayout 27 - (NSMutableArray *)maxYs{ 28 29 if (_maxYs == nil) { 30 _maxYs = [NSMutableArray array]; 31 NSLog(@"%@",_maxYs); 32 33 } 34 35 return _maxYs; 36 } 37 38 /** 39 * 用来设置每一个对应位置的item属性 40 * 41 * @param indexPath 用来确定每一item具体位置 42 * 43 * @return 用来设置每一个item的属性 44 */ 45 -(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{ 46 //NSLog(@"调用了layoutAttributesForItemAtIndexPath"); 47 // 1.确定上左下右间距 48 49 UIEdgeInsets edge = UIEdgeInsetsMake(10, 10, 10, 10); 50 // 2.确定宽度 51 // 2.1确定列数 52 53 // 2.2确定行间距和列间距 54 CGFloat rowMargin = 10; 55 CGFloat colMargin = 10; 56 57 CGFloat itemW = (self.collectionView.frame.size.width - edge.left - edge.right - (column - 1)*colMargin)/column; 58 // 3.确定高度 59 // 3.1获取对应item的模型 60 LYShopModel *shop = self.shops[indexPath.item]; 61 // itemW/itemh = shop.width/shop.height; 62 63 CGFloat itemH = shop.height *itemW/shop.width; 64 65 // CGFloat itmeH = 100+ arc4random_uniform(100); 66 // 4.确定位置 67 68 // 4.1获取最小的最大y值 69 // 4.2用一个值来记录最小的最大y值 70 CGFloat minMaxY = MAXFLOAT; 71 // 4.3记录最小的最大的y值所在的列号; 72 NSInteger minMaxCol = 0; 73 for (int i = 0; i <column; i ++) { 74 CGFloat maxY = [self.maxYs[i]doubleValue]; 75 if (maxY < minMaxY) { 76 minMaxY = maxY; 77 minMaxCol = i; 78 } 79 } 80 // 4.4设置item的x值 81 CGFloat itemX = edge.left + (itemW + colMargin) *minMaxCol; 82 CGFloat itemY = minMaxY + rowMargin; 83 // 5.获取每一个对应位置的item的属性 84 UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; 85 // 6.设置属性的frame 86 attr.frame = CGRectMake(itemX, itemY, itemW, itemH); 87 // 7.累加最小的最大的y值 88 // minMaxY = CGRectGetMaxY(attr.frame); 89 self.maxYs[minMaxCol]= @(CGRectGetMaxY(attr.frame)); 90 91 92 93 // 8.返回属性 94 return attr; 95 96 } 97 /** 98 * 用来设置给定范围内所有的属性 99 * 100 * @param rect <#rect description#> 101 * 102 * @return <#return value description#> 103 */ 104 - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{ 105 // NSLog(@"调用了layoutAttributesForElementsInRect"); 106 // 0.清空原来的所有的值 107 // [self.maxYs removeAllObjects]; 108 // 1.设置数组的值 109 for (int i = 0 ; i <column;i ++) { 110 // [self.maxYs addObject:@(0)]; 111 self.maxYs[i]=@(0); 112 } 113 114 115 // 2.创建可变数组 116 NSMutableArray *attrs = [NSMutableArray array]; 117 118 // 119 // 3.获取所有的item的属性的个数 120 NSInteger count = [self.collectionView numberOfItemsInSection:0]; 121 // 4.遍历多次,添加对应的属性值 122 for (int i = 0; i < count; i ++ ) { 123 NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0]; 124 125 UICollectionViewLayoutAttributes *attr = [self layoutAttributesForItemAtIndexPath:indexPath]; 126 127 [attrs addObject:attr]; 128 // NSLog(@"%@",attr); 129 130 } 131 return attrs; 132 133 134 } 135 - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{ 136 // NSLog(@"调用了shouldInvalidateLayoutForBoundsChange"); 137 return YES; 138 } 139 /** 140 * 用来设置collectionView的滚动范围 141 * 142 * @return <#return value description#> 143 */ 144 145 - (CGSize)collectionViewContentSize{ 146 // NSLog(@"调用了collectionViewContentSize"); 147 // 1.获取最大最大y值 148 CGFloat maxMaxY = 0; 149 // 1.1.记录最大的最大y值 150 if (self.maxYs.count) { 151 maxMaxY = [self.maxYs[0]doubleValue]; 152 for (int i = 1; i < column; i ++) { 153 // 1.2获取每一个值 154 CGFloat maxY = [self.maxYs[i]doubleValue]; 155 if (maxY > maxMaxY) { 156 maxMaxY = maxY; 157 } 158 159 } 160 161 } 162 163 164 return CGSizeMake(0, maxMaxY); 165 166 167 } 168 169 @end
1 //LYShopModel文件 2 #import <Foundation/Foundation.h> 3 4 @interface LYShopModel : NSObject 5 @property(nonatomic,copy)NSString *icon; 6 @property(nonatomic,copy)NSString *price; 7 @property(nonatomic,assign)int height; 8 @property(nonatomic,assign)int width; 9 - (instancetype)initWithDict:(NSDictionary *)dict; 10 + (instancetype)shopWithDict:(NSDictionary *)dict; 11 12 @end 13 14 15 16 17 18 #import "LYShopModel.h" 19 20 @implementation LYShopModel 21 22 - (instancetype)initWithDict:(NSDictionary *)dict{ 23 24 if (self = [super init]) { 25 [self setValuesForKeysWithDictionary:dict]; 26 } 27 return self; 28 } 29 + (instancetype)shopWithDict:(NSDictionary *)dict{ 30 31 return [[self alloc]initWithDict:dict]; 32 } 33 34 @end
MDM相关内容