下拉刷新控件目前比较火的有好几种,本人用过MJRefresh 和 SVPullToRefresh,相对而言,前者比后者可定制化、拓展新都更高一点。因此本文着重讲一下MJRefresh的简单用法。
广泛性分为6种使用场景,分别对应:默认、动画图片、隐藏时间、隐藏时间和状态、自定义文字说明、以及自定义刷新控件。
下面就各种场景分别讲一下:
1、默认场景
包含刷新菊花、下拉说明、时间
使用代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#pragma mark UITableView + 下拉刷新 默认
- (
void
)example01
{
__weak __typeof(
self
) weakSelf =
self
;
// 设置回调(一旦进入刷新状态就会调用这个refreshingBlock)
self
.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
[weakSelf loadNewData];
}];
// 马上进入刷新状态
[
self
.tableView.mj_header beginRefreshing];
}
|
2、使用动画图片
PS:这里的动画并不是用gif实现的,而是利用序列帧(即若干图片组成一个不同状态下的图片数组,然后根据位置显示不同图片)去展现。
1
2
3
4
5
6
7
8
9
|
#pragma mark UITableView + 下拉刷新 动画图片
- (
void
)example02
{
// 设置回调(一旦进入刷新状态,就调用target的action,也就是调用self的loadNewData方法)
self
.tableView.mj_header = [MJChiBaoZiHeader headerWithRefreshingTarget:
self
refreshingAction:
@selector
(loadNewData)];
// 马上进入刷新状态
[
self
.tableView.mj_header beginRefreshing];
}
|
这里用大众点评吃包子图片为例,新建一个自定义类 MJChiBaoZiHeader,继承:MJRefreshGifHeader
#import "MJRefreshGifHeader.h"
@interface MJChiBaoZiHeader : MJRefreshGifHeader
@end
然后重写prepare方法,代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
- (
void
)prepare
{
[
super
prepare];
// 设置普通状态的动画图片
NSMutableArray
*idleImages = [
NSMutableArray
array];
for
(
NSUInteger
i = 1; i<=60; i++) {
UIImage *image = [UIImage imageNamed:[
NSString
stringWithFormat:@
"dropdown_anim__000%zd"
, i]];
[idleImages addObject:image];
}
[
self
setImages:idleImages forState:MJRefreshStateIdle];
// 设置即将刷新状态的动画图片(一松开就会刷新的状态)
NSMutableArray
*refreshingImages = [
NSMutableArray
array];
for
(
NSUInteger
i = 1; i<=3; i++) {
UIImage *image = [UIImage imageNamed:[
NSString
stringWithFormat:@
"dropdown_loading_0%zd"
, i]];
[refreshingImages addObject:image];
}
[
self
setImages:refreshingImages forState:MJRefreshStatePulling];
// 设置正在刷新状态的动画图片
[
self
setImages:refreshingImages forState:MJRefreshStateRefreshing];
}
|
关键点就是这里的两个图片数组,60是因为下拉控件默认拉动距离就是60距离,这里比较严谨,利用60张不同图片去对应每个距离点,当然实际中,我们可以缩减,不需要精确到每个距离点对应一张图片,这里个人自己决定。
这里需要先了解下,下拉的五种状态。如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/** 刷新控件的状态 */
typedef
NS_ENUM
(
NSInteger
, MJRefreshState) {
/** 普通闲置状态 */
MJRefreshStateIdle = 1,
/** 松开就可以进行刷新的状态 */
MJRefreshStatePulling,
/** 正在刷新中的状态 */
MJRefreshStateRefreshing,
/** 即将刷新的状态 */
MJRefreshStateWillRefresh,
/** 所有数据加载完毕,没有更多的数据了 */
MJRefreshStateNoMoreData
};
|
1
|
idleImages图片数组对应闲置下拉状态,表示下拉到临界值前的展示图片。
|
1
|
refreshingImages图片数组对应正在刷新时的动画展示图片,一般这里需要3~5张图片去模拟动画。<br><br>重写完<span
class
=
"s1"
>prepare方法,就可以实现动画了。<br><br></span>
|
3、下拉刷新 隐藏时间
这里与默认的区别就是不显示上次刷新时间,使用方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#pragma mark UITableView + 下拉刷新 隐藏时间
- (
void
)example03
{
// 设置回调(一旦进入刷新状态,就调用target的action,也就是调用self的loadNewData方法)
MJRefreshNormalHeader *header = [MJRefreshNormalHeader headerWithRefreshingTarget:
self
refreshingAction:
@selector
(loadNewData)];
// 设置自动切换透明度(在导航栏下面自动隐藏)
header.automaticallyChangeAlpha =
YES
;
// 隐藏时间
header.lastUpdatedTimeLabel.hidden =
YES
;
// 马上进入刷新状态
[header beginRefreshing];
// 设置header
self
.tableView.mj_header = header;
}
|
4、下拉刷新 隐藏状态和时间
这个场景一般适用于只需要动画展示,简洁清爽,也是用的蛮多的。
同样,处理很简单。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#pragma mark UITableView + 下拉刷新 隐藏状态和时间
- (
void
)example04
{
// 设置回调(一旦进入刷新状态,就调用target的action,也就是调用self的loadNewData方法)
MJChiBaoZiHeader *header = [MJChiBaoZiHeader headerWithRefreshingTarget:
self
refreshingAction:
@selector
(loadNewData)];
// 隐藏时间
header.lastUpdatedTimeLabel.hidden =
YES
;
// 隐藏状态
header.stateLabel.hidden =
YES
;
// 马上进入刷新状态
[header beginRefreshing];
// 设置header
self
.tableView.mj_header = header;
}
|
5、下拉刷新 自定义文字
想自己DIY个性文字描述,一样很简单。
不管是文字text、文字大小、还是颜色都一句话搞定。
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
|
#pragma mark UITableView + 下拉刷新 自定义文字
- (
void
)example05
{
// 设置回调(一旦进入刷新状态,就调用target的action,也就是调用self的loadNewData方法)
MJRefreshNormalHeader *header = [MJRefreshNormalHeader headerWithRefreshingTarget:
self
refreshingAction:
@selector
(loadNewData)];
// 设置文字
[header setTitle:@
"快扯我,快点"
forState:MJRefreshStateIdle];
[header setTitle:@
"数据要来啦"
forState:MJRefreshStatePulling];
[header setTitle:@
"服务器正在狂奔 ..."
forState:MJRefreshStateRefreshing];
// 设置字体
header.stateLabel.font = [UIFont systemFontOfSize:15];
header.lastUpdatedTimeLabel.font = [UIFont systemFontOfSize:14];
// 设置颜色
header.stateLabel.textColor = [UIColor redColor];
header.lastUpdatedTimeLabel.textColor = [UIColor grayColor];
// 马上进入刷新状态
[header beginRefreshing];
// 设置刷新控件
self
.tableView.mj_header = header;
}
|
6、下拉刷新 自定义刷新控件
上面的都不够玩,怎么办,没关系,还有最后一种更定制化的方法:自己加控件样式。
这里不限于任何控件,我们可以在头部的这片区域,尽情添加Subviews,但记住一点,高度千万不要吵过header高度(默认60)。
除了控件,甚至可以自己绘制动画等等。
实现原理:同样先自定义自己的类,继承 MJRefreshHeader
重写 prepare 方法,再重写 placeSubviews 方法 设置位置。
代码:
a、定义控件属性
1
2
3
4
5
6
|
@interface
MJDIYHeader()
@property
(weak,
nonatomic
) UILabel *label;
@property
(weak,
nonatomic
) UISwitch *s;
@property
(weak,
nonatomic
) UIImageView *logo;
@property
(weak,
nonatomic
) UIActivityIndicatorView *loading;
@end
|
b、重写prepare方法
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
|
#pragma mark 在这里做一些初始化配置(比如添加子控件)
- (
void
)prepare
{
[
super
prepare];
// 设置控件的高度
self
.mj_h = 50;
// 添加label
UILabel *label = [[UILabel alloc] init];
label.textColor = [UIColor colorWithRed:1.0 green:0.5 blue:0.0 alpha:1.0];
label.font = [UIFont boldSystemFontOfSize:16];
label.textAlignment =
NSTextAlignmentCenter
;
[
self
addSubview:label];
self
.label = label;
// 打酱油的开关
UISwitch *s = [[UISwitch alloc] init];
[
self
addSubview:s];
self
.s = s;
// logo
UIImageView *logo = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@
"Logo"
]];
logo.contentMode = UIViewContentModeScaleAspectFit;
[
self
addSubview:logo];
self
.logo = logo;
// loading
UIActivityIndicatorView *loading = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[
self
addSubview:loading];
self
.loading = loading;
}
|
c、重写 placeSubviews
1
2
3
4
5
6
7
8
9
10
11
12
|
#pragma mark 在这里设置子控件的位置和尺寸
- (
void
)placeSubviews
{
[
super
placeSubviews];
self
.label.frame =
self
.bounds;
self
.logo.bounds = CGRectMake(0, 0,
self
.bounds.size.width, 100);
self
.logo.center = CGPointMake(
self
.mj_w * 0.5, -
self
.logo.mj_h + 20);
self
.loading.center = CGPointMake(
self
.mj_w - 30,
self
.mj_h * 0.5);
}
|
d、根据下拉位移,自定义不同位移的控件展示,比如显示不同文字,颜色等
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
|
#pragma mark 监听控件的刷新状态
- (
void
)setState:(MJRefreshState)state
{
MJRefreshCheckState;
switch
(state) {
case
MJRefreshStateIdle:
[
self
.loading stopAnimating];
[
self
.s setOn:
NO
animated:
YES
];
self
.label.text = @
"赶紧下拉吖(开关是打酱油滴)"
;
break
;
case
MJRefreshStatePulling:
[
self
.loading stopAnimating];
[
self
.s setOn:
YES
animated:
YES
];
self
.label.text = @
"赶紧放开我吧(开关是打酱油滴)"
;
break
;
case
MJRefreshStateRefreshing:
[
self
.s setOn:
YES
animated:
YES
];
self
.label.text = @
"加载数据中(开关是打酱油滴)"
;
[
self
.loading startAnimating];
break
;
default
:
break
;
}
}
|
上拉刷新加载其实和下拉是同理,只不过区别就是:
self.tableView.mj_header 变成 self.tableView.mj_footer,后面的类也由
MJRefreshNormalHeader 变成 MJRefreshAutoNormalFooter。
实现原理是相同的。
参考链接、下载源码:https://github.com/CoderMJLee/MJRefresh