不规则瀑布流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@protocol WaterLayoutDelegate <NSObject>

@required
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath;




@end
@interface WJY_WaterFallLayout : UICollectionViewLayout
@property (nonatomic, assign) id<WaterLayoutDelegate> delegate;
// 行数
@property (nonatomic, assign) NSInteger lineCount;
// 水平间距
@property (nonatomic, assign) CGFloat verticalSpacing;
// 垂直间距
@property (nonatomic, assign) CGFloat horizontalSpacing;
@property (nonatomic, assign) UIEdgeInsets sectionInset;
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#import "WJY_WaterFallLayout.h"

@interface WJY_WaterFallLayout()
@property (nonatomic, retain) NSMutableArray *heights;
@property (nonatomic, retain) NSMutableArray *originX;
@property (nonatomic, retain) NSMutableDictionary *itemsArrange;

@property (nonatomic, retain) NSMutableDictionary *itemsInitialArrange;

@end
@implementation WJY_WaterFallLayout
#pragma mark - 重写,应 始终调用子类
- (void)prepareLayout
{
// 如果item 是0 返回
NSInteger cellCount = [self.collectionView numberOfItemsInSection:0];
if (cellCount == 0) {
return ;
}
// 调转系统的协议方法 并设置代理
self.delegate = (id<WaterLayoutDelegate>)self.collectionView.delegate;

self.itemsArrange = [NSMutableDictionary dictionary];
self.itemsInitialArrange = [NSMutableDictionary dictionary];

[self initAllarrays];

for (NSInteger i = 0; i < cellCount; i++) {
[
self layoutForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
}

}
#pragma 初始化所以数组
- (void)initAllarrays
{

self.heights = [NSMutableArray array];
self.originX = [NSMutableArray array];
// item宽度
CGFloat itemWidth = ([UIScreen mainScreen].bounds.size.width - self.sectionInset.left - self.sectionInset.right - (self.lineCount - 1) * self.horizontalSpacing) / self.lineCount;

for (NSInteger i = 0; i < self.lineCount; i++) {

// 循环添加 每行的每个top的点到 height数组中
[self.heights addObject:[NSNumber numberWithDouble:self.sectionInset.top]];

//设置oringin_x 为0
CGFloat oringin_x = 0.0;

if (i == 0) {
//i = 0 x点 = left;
oringin_x = self.sectionInset.left;
} else {
// x = i + item宽 + 横向宽度
oringin_x = [self.originX[i - 1] doubleValue] + itemWidth + self.horizontalSpacing;
}
// 把得到的点加到 x数组中
[self.originX addObject:[NSNumber numberWithDouble: oringin_x]];
}

}
#pragma mark - itme设置
- (void)layoutForItemAtIndexPath:(NSIndexPath *)indexPath
{

CGRect rect = CGRectZero;
// 协议方法
CGSize size = [self.delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];

rect.size.height = size.height;

rect.size.width = ([UIScreen mainScreen].bounds.size.width - self.sectionInset.left - self.sectionInset.right - (self.lineCount - 1) * self.horizontalSpacing) / self.lineCount;

NSInteger index = [self getLowerHeightRowIndex:self.heights];

rect.origin.x = [self.originX[index] doubleValue];
rect.origin.y = [self.heights[index] doubleValue];

CGFloat newHeight = rect.origin.y + rect.size.height + self.verticalSpacing;

[self.heights replaceObjectAtIndex:index withObject:[NSNumber numberWithDouble: newHeight]];

[self.itemsArrange setObject:indexPath forKey:NSStringFromCGRect(rect)];

[self.itemsInitialArrange setObject:indexPath forKey:NSStringFromCGRect(CGRectMake(rect.origin.x, rect.origin.y - [UIScreen mainScreen].bounds.size.height, rect.size.width, rect.size.height))];
}
#pragma mark - 子类必须重写此方法并使用它来返回的宽度和高度的视图的内容。这些值表示的宽度和高度的所有内容,视图使用此信息来配置其自身内容的大小,以便滚动。
- (CGSize)collectionViewContentSize
{


CGFloat heightest = [self getHeightest:self.heights];

CGSize size = CGSizeMake(0, heightest);

return size;
}
#pragma mark - 设置布局信息
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {

UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

NSArray *keyArr = self.itemsArrange.allKeys;

for (NSString *rectStr in keyArr) {

if (self.itemsArrange[rectStr] != indexPath) {
continue;
}

CGRect rect = CGRectFromString(rectStr);

attributes.frame = rect;

break;

}

return attributes;
}
#pragma mark - 重新自定义layout
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {
// layout初始化方法
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:itemIndexPath];

NSArray *keyArr = self.itemsArrange.allKeys;

for (NSString *rectStr in keyArr) {
// item的rect信息和布局信息不等 就跳出本次循环
if (self.itemsInitialArrange[rectStr] != itemIndexPath) {
continue;
}

CGRect rect = CGRectFromString(rectStr);

attributes.frame = rect;

break;

}

return attributes;
}

#pragma mark - 布局属性返回数组 视图在给定矩形
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {

CGFloat up = rect.origin.y;

CGFloat down = rect.origin.y + rect.size.height;

NSMutableArray *attributes = [NSMutableArray array];

for (NSString *rectStr in self.itemsArrange) {

CGRect itemRect = CGRectFromString(rectStr);

if (itemRect.origin.y <= down && itemRect.origin.y + itemRect.size.height >= up) {

NSIndexPath *indexPath = [self.itemsArrange objectForKey:rectStr];

//设置布局信息 添加到数组里
[attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
}
}

return attributes;
}
# pragma mark - 获取低行高
- (NSInteger)getLowerHeightRowIndex:(NSMutableArray *)height {

if (height.count == 0) {
return 0;
}

NSInteger index = 0;

CGFloat heightest = [height[0] doubleValue];

for (NSInteger i = 1; i < height.count; i++) {
// 判定获取低行位置
index = heightest > [height[i] doubleValue] ? i : index;
}

return index;
}
# pragma mark - 获取高度
- (CGFloat)getHeightest:(NSMutableArray *)height {

if (height.count == 0) {
return 0;
}

CGFloat heightest = self.sectionInset.top;
// 遍历最高点
for (NSInteger i = 0; i < height.count; i++) {
// 如果heightest为最高点返回返回 如果不是则返回height
heightest = heightest > [height[i] doubleValue] ? heightest : [height[i] doubleValue];
}

return heightest;
}


@end
文章目录
|