- 项目中经常会用到上拉下拉刷新,通常使用<MJRefresh>框架
- 一般公司都会对自己app的上拉下拉刷新作特性化定制,而且全局多处用到.所以需要对自定义的上拉下拉刷新进行封装
代码如下(文字效果)
下拉刷新封装 (继承MJRefreshNormalHeader)
.h文件
#import <MJRefresh/MJRefresh.h>
@interface XMGRefreshHeader : MJRefreshNormalHeader
@end
.m文件
#import "XMGRefreshHeader.h"
@interface XMGRefreshHeader()
/** logo */
@property (nonatomic, weak) UIImageView *logo;
@end
@implementation XMGRefreshHeader
/**
* 初始化
*/
- (void)prepare
{
[super prepare];
self.automaticallyChangeAlpha = YES;
// 修改时间文字的颜色
self.lastUpdatedTimeLabel.textColor = [UIColor orangeColor];
// 修改刷新状态的颜色
self.stateLabel.textColor = [UIColor orangeColor];
// 设置state状态下的文字
[self setTitle:@"赶紧下拉吧" forState:MJRefreshStateIdle];
[self setTitle:@"赶紧松开吧" forState:MJRefreshStatePulling];
[self setTitle:@"正在加载数据..." forState:MJRefreshStateRefreshing];
// 隐藏时间
// self.lastUpdatedTimeLabel.hidden = YES;
// 隐藏刷新状态
// self.stateLabel.hidden = YES;
// 添加控件
[self addSubview:[[UISwitch alloc] init]];
// 添加logo
UIImageView *logo = [[UIImageView alloc] init];
logo.image = [UIImage imageNamed:@"bd_logo1"];
[self addSubview:logo];
self.logo = logo;
}
/**
* 摆放子控件
*/
- (void)placeSubviews
{
[super placeSubviews];
self.logo.xmg_width = self.xmg_width;
self.logo.xmg_height = 50;
self.logo.xmg_x = 0;
self.logo.xmg_y = - 50; // 自己控制
}
上拉刷新封装(继承MJRefreshAutoNormalFooter)
.h文件
#import <MJRefresh/MJRefresh.h>
@interface XMGRefreshFooter : MJRefreshAutoNormalFooter
@end
.m文件
#import "XMGRefreshFooter.h"
@implementation XMGRefreshFooter
- (void)prepare
{
[super prepare];
self.stateLabel.textColor = [UIColor redColor];
[self addSubview:[UIButton buttonWithType:UIButtonTypeContactAdd]];
// 刷新控件出现一半就会进入刷新状态
// self.triggerAutomaticallyRefreshPercent = 0.5;
// 不要自动刷新
// self.automaticallyRefresh = NO;
}
@end
项目中使用
@interface XMGAllViewController ()
/** 所有的帖子数据 */
@property (nonatomic, strong) NSMutableArray<XMGTopic *> *topics;
/** 下拉刷新的提示文字 */
@property (nonatomic, weak) UILabel *label;
/** maxtime : 用来加载下一页数据 */
@property (nonatomic, copy) NSString *maxtime;
/** 任务管理者 */
@property (nonatomic, strong) AFHTTPSessionManager *manager;
@end
- (AFHTTPSessionManager *)manager
{
if (!_manager) {
_manager = [AFHTTPSessionManager manager];
}
return _manager;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setupRefresh];
}
// 刷新
- (void)setupRefresh
{
self.tableView.mj_header = [XMGRefreshHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewTopics)];
// 希望一进来就刷新
[self.tableView.mj_header beginRefreshing];
self.tableView.mj_footer = [XMGRefreshFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreTopics)];
}
#pragma mark - 数据加载
- (void)loadNewTopics
{
// 取消所有请求
[self.manager.tasks makeObjectsPerformSelector:@selector(cancel)];
// 参数
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"a"] = @"list";
params[@"c"] = @"data";
// 发送请求
[[AFHTTPSessionManager manager] GET:@"http://api.budejie.com/api/api_open.php" parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
// 存储maxtime(方便用来加载下一页数据)
self.maxtime = responseObject[@"info"][@"maxtime"];
// 字典数组 -> 模型数组
self.topics = [XMGTopic mj_objectArrayWithKeyValuesArray:responseObject[@"list"]];
// 刷新表格
[self.tableView reloadData];
// 让[刷新控件]结束刷新
[self.tableView.mj_header endRefreshing];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
XMGLog(@"请求失败 - %@", error);
// 让[刷新控件]结束刷新
[self.tableView.mj_header endRefreshing];
}];
}
- (void)loadMoreTopics
{
// 取消所有的请求
[self.manager.tasks makeObjectsPerformSelector:@selector(cancel)];
// 参数
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"a"] = @"list";
params[@"c"] = @"data";
params[@"maxtime"] = self.maxtime;
// 发送请求
[[AFHTTPSessionManager manager] GET:@"http://api.budejie.com/api/api_open.php" parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
// 存储这页对应的maxtime
self.maxtime = responseObject[@"info"][@"maxtime"];
// 字典数组 -> 模型数组
NSArray<XMGTopic *> *moreTopics = [XMGTopic mj_objectArrayWithKeyValuesArray:responseObject[@"list"]];
[self.topics addObjectsFromArray:moreTopics];
// 刷新表格
[self.tableView reloadData];
// 让[刷新控件]结束刷新
[self.tableView.mj_footer endRefreshing];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
XMGLog(@"请求失败 - %@", error);
// 让[刷新控件]结束刷新
[self.tableView.mj_footer endRefreshing];
}];
}
拓展分析
1. addObject:和addObjectsFromArray:的区别
self.topics = @[20, 19, 18]
moreTopics = @[17, 16, 15]
self.topics = @[20, 19, 18, @[17, 16, 15]]
[self.topics addObject:moreTopics];
self.topics = @[20, 19, 18, 17, 16, 15]
[self.topics addObjectsFromArray:moreTopics];
2. 常见分页方法
方法一:
缺点:可能加载重数据
方法二:
大多数公司采用的方法
原理:明确的告诉服务器我数据加载到哪
分页在项目示例中的解析
在下拉的 - (void)loadNewTopics 方法中 ,存储一下它的maxtime
// 存储maxtime(方便用来加载下一页数据)
self.maxtime = responseObject[@"info"][@"maxtime"];
在上拉 - (void)loadMoreTopics 中要传maxtime给后台,同时maxtime的值根据不断地恶上拉要不断更新,所以在上拉后,将后台返回的maxtime不断存储下来
// 存储这页对应的maxtime
self.maxtime = responseObject[@"info"][@"maxtime"];
3. 上拉下拉刷新出现的一些问题
- 当上拉下拉同时出现时,会出现数据漏掉问题
解决:
上拉时,取消其它的所有请求 ,同时取消刷新控件
下拉时,取消其它的所有请求 ,同时取消刷新控件
// 所有的任务被任务管理者统一管理
// 此句代码的意思就是取消其它所有的请求
// 一个请求任务被取消了(cancel), 会自动调用AFN请求的failure这个block
// 所以不需要再单独去写取消刷新控件
[self.manager.tasks makeObjectsPerformSelector:@selector(cancel)];
4. 子类化AFHTTPSessionManager
需求:因为有可能项目中多地方使用,并且会做一些统一化设置,所以将其抽出一个子类,方便项目中使用(官方建议如此使用)
代码如下:
#import <AFNetworking/AFNetworking.h>
@interface XMGHTTPSessionManager : AFHTTPSessionManager
@end
#import "XMGHTTPSessionManager.h"
@implementation XMGHTTPSessionManager
- (instancetype)initWithBaseURL:(NSURL *)url
{
if (self = [super initWithBaseURL:url]) {
// self.securityPolicy.validatesDomainName = NO;
// self.responseSerializer = nil;
// self.requestSerializer = nil;
}
return self;
}
@end