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