forked from 151283250/MJRefresh
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMJRefreshBaseView.m
301 lines (256 loc) · 8.87 KB
/
MJRefreshBaseView.m
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
//
// MJRefreshBaseView.m
// MJRefresh
//
// Created by mj on 13-3-4.
// Copyright (c) 2013年 itcast. All rights reserved.
//
#import "MJRefreshBaseView.h"
#import "MJRefreshConst.h"
@interface MJRefreshBaseView()
{
BOOL _hasInitInset;
}
/**
交给子类去实现
*/
// 合理的Y值
- (CGFloat)validY;
// view的类型
- (MJRefreshViewType)viewType;
@end
@implementation MJRefreshBaseView
#pragma mark 创建一个UILabel
- (UILabel *)labelWithFontSize:(CGFloat)size
{
UILabel *label = [[UILabel alloc] init];
label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
label.font = [UIFont boldSystemFontOfSize:size];
label.textColor = MJRefreshLabelTextColor;
label.backgroundColor = [UIColor clearColor];
label.textAlignment = NSTextAlignmentCenter;
return label;
}
#pragma mark - 初始化方法
- (instancetype)initWithScrollView:(UIScrollView *)scrollView
{
if (self = [super init]) {
self.scrollView = scrollView;
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
if (!_hasInitInset) {
_scrollViewInitInset = _scrollView.contentInset;
[self observeValueForKeyPath:MJRefreshContentSize ofObject:nil change:nil context:nil];
_hasInitInset = YES;
if (_state == MJRefreshStateWillRefreshing) {
[self setState:MJRefreshStateRefreshing];
}
}
}
#pragma mark 构造方法
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// 1.自己的属性
self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
self.backgroundColor = [UIColor clearColor];
// 2.时间标签
[self addSubview:_lastUpdateTimeLabel = [self labelWithFontSize:12]];
// 3.状态标签
[self addSubview:_statusLabel = [self labelWithFontSize:13]];
// 4.箭头图片
UIImageView *arrowImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:kSrcName(@"arrow.png")]];
arrowImage.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
[self addSubview:_arrowImage = arrowImage];
// 5.指示器
UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityView.bounds = arrowImage.bounds;
activityView.autoresizingMask = arrowImage.autoresizingMask;
[self addSubview:_activityView = activityView];
// 6.设置默认状态
[self setState:MJRefreshStateNormal];
}
return self;
}
#pragma mark 设置frame
- (void)setFrame:(CGRect)frame
{
frame.size.height = MJRefreshViewHeight;
[super setFrame:frame];
CGFloat w = frame.size.width;
CGFloat h = frame.size.height;
if (w == 0 || _arrowImage.center.y == h * 0.5) return;
CGFloat statusX = 0;
CGFloat statusY = 5;
CGFloat statusHeight = 20;
CGFloat statusWidth = w;
// 1.状态标签
_statusLabel.frame = CGRectMake(statusX, statusY, statusWidth, statusHeight);
// 2.时间标签
CGFloat lastUpdateY = statusY + statusHeight + 5;
_lastUpdateTimeLabel.frame = CGRectMake(statusX, lastUpdateY, statusWidth, statusHeight);
// 3.箭头
CGFloat arrowX = w * 0.5 - 100;
_arrowImage.center = CGPointMake(arrowX, h * 0.5);
// 4.指示器
_activityView.center = _arrowImage.center;
}
- (void)setBounds:(CGRect)bounds
{
bounds.size.height = MJRefreshViewHeight;
[super setBounds:bounds];
}
#pragma mark - UIScrollView相关
#pragma mark 设置UIScrollView
- (void)setScrollView:(UIScrollView *)scrollView
{
// 移除之前的监听器
[_scrollView removeObserver:self forKeyPath:MJRefreshContentOffset context:nil];
// 监听contentOffset
[scrollView addObserver:self forKeyPath:MJRefreshContentOffset options:NSKeyValueObservingOptionNew context:nil];
// 设置scrollView
_scrollView = scrollView;
[_scrollView addSubview:self];
}
#pragma mark 监听UIScrollView的contentOffset属性
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (![MJRefreshContentOffset isEqualToString:keyPath]) return;
if (!self.userInteractionEnabled || self.alpha <= 0.01 || self.hidden
|| _state == MJRefreshStateRefreshing) return;
// scrollView所滚动的Y值 * 控件的类型(头部控件是-1,尾部控件是1)
CGFloat offsetY = _scrollView.contentOffset.y * self.viewType;
CGFloat validY = self.validY;
if (offsetY <= validY) return;
if (_scrollView.isDragging) {
CGFloat validOffsetY = validY + MJRefreshViewHeight;
if (_state == MJRefreshStatePulling && offsetY <= validOffsetY) {
// 转为普通状态
[self setState:MJRefreshStateNormal];
// 通知代理
if ([_delegate respondsToSelector:@selector(refreshView:stateChange:)]) {
[_delegate refreshView:self stateChange:MJRefreshStateNormal];
}
// 回调
if (_refreshStateChangeBlock) {
_refreshStateChangeBlock(self, MJRefreshStateNormal);
}
} else if (_state == MJRefreshStateNormal && offsetY > validOffsetY) {
// 转为即将刷新状态
[self setState:MJRefreshStatePulling];
// 通知代理
if ([_delegate respondsToSelector:@selector(refreshView:stateChange:)]) {
[_delegate refreshView:self stateChange:MJRefreshStatePulling];
}
// 回调
if (_refreshStateChangeBlock) {
_refreshStateChangeBlock(self, MJRefreshStatePulling);
}
}
} else { // 即将刷新 && 手松开
if (_state == MJRefreshStatePulling) {
// 开始刷新
[self setState:MJRefreshStateRefreshing];
// 通知代理
if ([_delegate respondsToSelector:@selector(refreshView:stateChange:)]) {
[_delegate refreshView:self stateChange:MJRefreshStateRefreshing];
}
// 回调
if (_refreshStateChangeBlock) {
_refreshStateChangeBlock(self, MJRefreshStateRefreshing);
}
}
}
}
#pragma mark 设置状态
- (void)setState:(MJRefreshState)state
{
if (_state != MJRefreshStateRefreshing) {
// 存储当前的contentInset
_scrollViewInitInset = _scrollView.contentInset;
}
// 1.一样的就直接返回
if (_state == state) return;
// 2.根据状态执行不同的操作
switch (state) {
case MJRefreshStateNormal: // 普通状态
// 显示箭头
_arrowImage.hidden = NO;
// 停止转圈圈
[_activityView stopAnimating];
// 说明是刚刷新完毕 回到 普通状态的
if (MJRefreshStateRefreshing == _state) {
// 通知代理
if ([_delegate respondsToSelector:@selector(refreshViewEndRefreshing:)]) {
[_delegate refreshViewEndRefreshing:self];
}
// 回调
if (_endStateChangeBlock) {
_endStateChangeBlock(self);
}
}
break;
case MJRefreshStatePulling:
break;
case MJRefreshStateRefreshing:
// 开始转圈圈
[_activityView startAnimating];
// 隐藏箭头
_arrowImage.hidden = YES;
_arrowImage.transform = CGAffineTransformIdentity;
// 通知代理
if ([_delegate respondsToSelector:@selector(refreshViewBeginRefreshing:)]) {
[_delegate refreshViewBeginRefreshing:self];
}
// 回调
if (_beginRefreshingBlock) {
_beginRefreshingBlock(self);
}
break;
default:
break;
}
// 3.存储状态
_state = state;
}
#pragma mark - 状态相关
#pragma mark 是否正在刷新
- (BOOL)isRefreshing
{
return MJRefreshStateRefreshing == _state;
}
#pragma mark 开始刷新
- (void)beginRefreshing
{
if (self.window) {
[self setState:MJRefreshStateRefreshing];
} else {
_state = MJRefreshStateWillRefreshing;
}
}
#pragma mark 结束刷新
- (void)endRefreshing
{
[self setState:MJRefreshStateNormal];
}
#pragma mark - 随便实现
- (CGFloat)validY { return 0;}
- (MJRefreshViewType)viewType {return MJRefreshViewTypeHeader;}
- (void)free
{
[_scrollView removeObserver:self forKeyPath:MJRefreshContentOffset];
}
- (void)removeFromSuperview
{
[self free];
_scrollView = nil;
[super removeFromSuperview];
}
- (void)endRefreshingWithoutIdle
{
[self endRefreshing];
}
@end