1 #import "ViewController.h" 2 #import "Model.h" 3 #import "MyCollectionViewCell.h" 4 #import "UIImageView+WebCache.h" 5 #import "CustomLayout.h" 6 @interface ViewController ()<UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout,CustomLayoutDelegate> 7 8 ///声明一个数组用于存储model的数据类 9 @property (nonatomic,strong)NSMutableArray *saveModelArray; 10 11 @end 12 13 @implementation ViewController 14 15 - (void)viewDidLoad { 16 [super viewDidLoad]; 17 // Do any additional setup after loading the view, typically from a nib. 18 19 //首先知道要显示的数据是数组套字典的格式 20 //创建Model类用于处理数据 21 //解析数据 22 [self analysizeData]; 23 24 //创建UICollectionView 25 [self createCollectionView]; 26 27 //现在效果图片发虚,不是我们真正想要的一个效果,用户体验相当不好,所以说我们需要自定义flowLayout显示图片 28 29 30 31 32 33 34 } 35 36 #pragma mark - 创建UICollectionView(在创建此视图之前必须设置UICollectionViewFlowLayout进行布局) 37 - (void)createCollectionView{ 38 /* 39 //1.创建UICollectionViewFlowLayout 40 UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; 41 //设置行间距 42 layout.minimumLineSpacing = 10; 43 //设置列间距的 44 layout.minimumInteritemSpacing = 10; 45 //设置item大小的 46 layout.itemSize = CGSizeMake(100, 100); 47 //设置视图距离上左下右的一个距离 48 layout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10); 49 50 //设置头部和尾部的高度 51 layout.headerReferenceSize = CGSizeMake(10, 10); 52 layout.footerReferenceSize = CGSizeMake(10, 10); 53 //设置滚动方向 54 layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; 55 */ 56 57 //使用自定义的layout进行布局 58 CustomLayout *layout = [[CustomLayout alloc] init]; 59 layout.delegate = self; 60 61 //设置布局的一个宽度 62 CGFloat width = ([[UIScreen mainScreen] bounds].size.width - 40)/3; 63 //设置item的一个大小 64 layout.itemSize = CGSizeMake(width, width); 65 //设置距离上下左右的间距 66 layout.sectionInsets = UIEdgeInsetsMake(10, 10, 10, 10); 67 68 layout.insertItemSpacing = 10; 69 layout.numberOfColumns = 3; 70 71 72 //创建UICollectionView 73 UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:[[UIScreen mainScreen] bounds] collectionViewLayout:layout]; 74 collectionView.delegate = self; 75 collectionView.dataSource = self; 76 collectionView.backgroundColor = [UIColor whiteColor]; 77 [self.view addSubview:collectionView]; 78 79 80 //千万不要忘记注册cell 81 [collectionView registerClass:[MyCollectionViewCell class] forCellWithReuseIdentifier:@"MyCollectionViewCell"]; 82 83 84 85 } 86 87 //设置item的高度 88 - (CGFloat)heightItemForIndexpath:(NSIndexPath *)indexPath{ 89 90 //获取model的对象 91 Model *model = _saveModelArray[indexPath.row]; 92 93 CGFloat width = ([UIScreen mainScreen].bounds.size.width - 40)/3; 94 95 CGFloat height = (model.height / model.width) * width; 96 97 return height; 98 99 } 100 101 #pragma mark - 实现相关的代理方法 102 //设置item的数量 103 - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ 104 105 return _saveModelArray.count; 106 } 107 //设置区的个数 108 - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{ 109 return 1; 110 } 111 //设置cell的一个样式 112 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ 113 114 //重用池里取出与之对应的cell 115 MyCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"MyCollectionViewCell" forIndexPath:indexPath]; 116 cell.backgroundColor = [UIColor whiteColor]; 117 118 //设置cell上显示的内容 119 //首先取出model对象 120 Model *model = _saveModelArray[indexPath.row]; 121 //然后将model对象中字符串类型的url转换成NSURL类型,以备使用 122 NSURL *url = [NSURL URLWithString:model.thumbURL]; 123 124 [cell.imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"placeHoderImage.png"]]; 125 126 127 128 129 return cell; 130 131 } 132 133 #pragma mark - 解析数据 134 - (void)analysizeData{ 135 136 //读取文件 137 NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Data" ofType:@"json"]; 138 139 //因为准备的数据是json数据,所以解析要遵循json数据的解析方式 140 NSData *data = [NSData dataWithContentsOfFile:filePath]; 141 NSMutableArray *array = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; 142 //给数组初始化 143 self.saveModelArray = [NSMutableArray array]; 144 //使用for..in遍历取出数组中的字典,然后赋值给model,存储起来 145 for (NSDictionary *dic in array) { 146 //使用kvc给model赋值 147 Model *model = [[Model alloc] init]; 148 [model setValuesForKeysWithDictionary:dic]; 149 [_saveModelArray addObject:model]; 150 } 151 152 NSLog(@"%@",_saveModelArray); 153 154 155 } 156 157 - (void)didReceiveMemoryWarning { 158 [super didReceiveMemoryWarning]; 159 // Dispose of any resources that can be recreated. 160 } 161 162 @end
1 #import <UIKit/UIKit.h> 2 3 //第一步:创建继承与UICollectionViewLayout的类,声明一个协议,只是先一个代理方法 4 5 @protocol CustomLayoutDelegate <NSObject> 6 7 //用于获取item的高度 8 - (CGFloat)heightItemForIndexpath:(NSIndexPath *)indexPath; 9 10 @end 11 12 13 @interface CustomLayout : UICollectionViewLayout 14 15 //第二步:设置相关的属性(设置外部可以访问到的) 16 ///item的大小 17 @property (nonatomic,assign)CGSize itemSize; 18 ///设置collectionView的内间距 19 @property (nonatomic,assign)UIEdgeInsets sectionInsets; 20 21 ///item间距的设置 22 @property (nonatomic,assign)CGFloat insertItemSpacing; 23 ///列的数目 24 @property (nonatomic,assign)NSInteger numberOfColumns; 25 26 ///代理 27 @property (nonatomic,weak)id <CustomLayoutDelegate>delegate; 28 29 30 31 32 @end
1 #import "CustomLayout.h" 2 3 //第三步:声明一些不暴露在外部使用的属性,只有当前文件可以使用的 4 @interface CustomLayout () 5 6 ///获取item的总数量 7 @property (nonatomic,assign)NSInteger numberOfItems; 8 9 ///存储每一列高度的数组 10 @property (nonatomic,strong)NSMutableArray *columnHeights; 11 12 ///存储距离上下左右的数组(x,y,w,h) 13 @property (nonatomic,strong)NSMutableArray *itemAtrributes; 14 15 ///存储item的x值 16 @property (nonatomic,assign)CGFloat detalX; 17 18 ///存储item相对应的y值 19 @property (nonatomic,assign)CGFloat detalY; 20 21 ///记录最短的列 22 @property (nonatomic,assign)NSInteger shortestIndex; 23 24 ///获取最长列的索引值 25 - (NSInteger)p_indexForLongestColumn; 26 27 ///获取最短列的索引值 28 - (NSInteger)p_indexForShortestColumn; 29 30 31 32 @end 33 34 @implementation CustomLayout 35 36 //第四步:懒加载一些数据源 37 - (NSMutableArray *)columnHeights{ 38 if (!_columnHeights) { 39 self.columnHeights = [NSMutableArray array]; 40 } 41 42 return _columnHeights; 43 } 44 45 - (NSMutableArray *)itemAtrributes{ 46 if (!_itemAtrributes) { 47 self.itemAtrributes = [NSMutableArray array]; 48 } 49 50 return _itemAtrributes; 51 } 52 53 //第五步:实现获取最长列的方法 54 - (NSInteger)p_indexForLongestColumn{ 55 //定义一个变量用于记录哪一列是最长列 56 NSInteger longestIndex = 0; 57 //当前最长列的一个高度 58 CGFloat longestHeight = 0; 59 60 //遍历数组取出相关数据然后返回 61 for (int i = 0; i < self.numberOfColumns; i++) { 62 //获取相关的一个高度 63 CGFloat currentHeight = [self.columnHeights[i] floatValue]; 64 65 //判断选出最高的一个高度 66 if (currentHeight > longestHeight) { 67 longestHeight = currentHeight; 68 longestIndex = i; 69 } 70 } 71 72 return longestIndex; 73 74 } 75 76 //第六步:实现获取最短列的一个方法 77 - (NSInteger)p_indexForShortestColumn{ 78 79 //记录索引 80 NSInteger shortestIndex = 0; 81 82 //记录最小的一个高度 83 CGFloat shortestHeight = MAXFLOAT; 84 85 //遍历赋值取出最小的下标 86 for (int i = 0; i < self.numberOfColumns; i++) { 87 //获取一个当前高度 88 CGFloat currentHeight = [self.columnHeights[i] floatValue]; 89 if (currentHeight < shortestHeight) { 90 shortestHeight = currentHeight; 91 shortestIndex = i; 92 } 93 } 94 return shortestIndex; 95 96 } 97 98 //第七步:实现给每一列添加top高度 99 - (void)addHeightWithColumns{ 100 101 //遍历取出相关的数值 102 for (int i = 0;i < self.numberOfColumns;i++){ 103 self.columnHeights[i] = @(self.sectionInsets.top); 104 } 105 106 } 107 108 //第八步:查找最短的列,并设置相关属性 109 // 查找最短的列,并设置相关属性 110 - (void)searchShortColumns 111 { 112 _shortestIndex = [self p_indexForShortestColumn]; 113 CGFloat shortestH = [self.columnHeights[_shortestIndex] floatValue]; 114 // 计算x值:内边距left + (item宽 + item的间距)* 索引 115 self.detalX = self.sectionInsets.left + (self.itemSize.width +self.insertItemSpacing) * _shortestIndex; 116 // 计算y值 117 self.detalY = shortestH + self.insertItemSpacing; 118 119 } 120 121 //第九步:查找最短的列,并设置相关属性 122 // 设置属性和frame 123 - (void)setFrame:(NSIndexPath *)indexPath 124 { 125 // 设置属性 126 UICollectionViewLayoutAttributes *layoutArr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; 127 // 保存item的高 128 CGFloat itemHeight = 0; 129 if (_delegate && [_delegate respondsToSelector:@selector(heightItemForIndexpath:)]) { 130 // 使用代理方法获取item的高 131 itemHeight = [_delegate heightItemForIndexpath:indexPath]; 132 } 133 // 设置frame 134 layoutArr.frame = CGRectMake(_detalX, _detalY, self.itemSize.width, itemHeight); 135 // 放入数组 136 [self.itemAtrributes addObject:layoutArr]; 137 // 更新高度 138 self.columnHeights[_shortestIndex] = @(_detalY +itemHeight); 139 } 140 141 //步骤十:在实现文件中必须要的实现三个方法 142 /* 143 - (void)prepareLayout 准备布局方法,在每个UICollectionViewLayout将要被使用的时候调用这个方法 144 145 - (CGSize)collectionViewContentSize 计算每个item的大小,会走很多次 146 147 - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 返回所有的item的位置信息和大小 148 */ 149 150 //第十一步:实现准备布局的代理方法 151 // 准备布局 152 - (void)prepareLayout 153 { 154 // 调用父类布局 155 [super prepareLayout]; 156 [self addHeightWithColumns]; 157 // 获取item的数量 158 self.numberOfItems = [self.collectionView numberOfItemsInSection:0]; 159 // 为每一个item设置frame和indexPath 160 for(int i = 0;i < self.numberOfItems;i++) 161 { 162 // 查找最短的列,并设置相关属性 163 [self searchShortColumns]; 164 // 设置indexPath 165 NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0]; 166 [self setFrame:indexPath]; 167 } 168 } 169 170 //第十二步:计算每个item的大小 171 // 计算每个item的大小 172 - (CGSize)collectionViewContentSize 173 { 174 // 获取最长高度索引 175 NSInteger longerstIndex = [self p_indexForLongestColumn]; 176 // 通过索引获取高度 177 CGFloat longestH = [self.columnHeights[longerstIndex] floatValue]; 178 // 获取collectionView的Size 179 CGSize contentSize = self.collectionView.frame.size; 180 // 最大高度+bottom 181 contentSize.height = longestH + self.sectionInsets.bottom; 182 return contentSize; 183 } 184 185 //第十三步:将每个item的布局返回 186 // 返回每一个item的布局 187 - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 188 { 189 // 返回每一个item的Attribute 190 return self.itemAtrributes; 191 192 } 193 194 195 196 @end
1 #import <UIKit/UIKit.h> 2 3 @interface MyCollectionViewCell : UICollectionViewCell 4 ///用来展示图片的控件 5 @property (nonatomic,strong)UIImageView *imageView; 6 7 @end
1 #import "MyCollectionViewCell.h" 2 3 @implementation MyCollectionViewCell 4 5 //重写初始化方法 6 - (instancetype)initWithFrame:(CGRect)frame{ 7 self = [super initWithFrame:frame]; 8 if (self) { 9 self.imageView = [[UIImageView alloc] init]; 10 [self.contentView addSubview:self.imageView]; 11 } 12 return self; 13 } 14 //设置控件的frame 15 - (void)layoutSubviews{ 16 [super layoutSubviews]; 17 self.imageView.frame = self.bounds; 18 } 19 20 @end
1 #import <Foundation/Foundation.h> 2 3 @interface Model : NSObject 4 5 ///图片的网址 6 @property (nonatomic,strong)NSString *thumbURL; 7 8 ///图片的宽 9 @property (nonatomic,assign)NSInteger width; 10 11 ///图片的高度 12 @property (nonatomic,assign)NSInteger height; 13 14 @end
1 #import "Model.h" 2 3 @implementation Model 4 5 - (void)setValue:(id)value forUndefinedKey:(NSString *)key{ 6 7 } 8 9 @end