一 刷新功能图和内部计算原理图
1 刷新功能图:
2 内部计算原理图
二 解析步骤
1 分析整个精华模块
2 真实数据请求部分
3 模型
4 先添加尾部刷新控件
5 再添加头部刷新控件
6 处理刷新业务逻辑
7 知识点补充
三 分析模块
1 从一个完整的app中可以看出,在精华模块中处于全部标题的部分数据包括了其它几部分的数据,内部有视频;声音;图片和段子,所以我们只需要将”全部”做好,就能很快的搞定其它模块了.
四 真实数据请求
1 大致步骤:
—-> 1 查看百思不得姐该部分的接口文档,获取URL.
—-> 2 查看接口文档中哪些是需要的请求参数(在百思不得姐的接口文档中:后面表明了ture是必须要的请求参数)
—-> 3 查看接口文档,请求方式是什么?这里是GET请求.
—-> 4 zing共请求数据分三大步骤:1> 创建会话管理者 2> 设置请求参数 3> 发送请求.
2 需要导入的框架
#import <AFNetworking.h>
#import <MJExtension/MJExtension.h>
#import <SVProgressHUD.h>
3 代码部分:加载更多数据;加载最新数据
—> 3.1 加载更多帖子
#pragma mark - 加载更多的帖子数
- (void)setUpMoreTopics
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
parameters[@"a"] = @"list";
parameters[@"c"] = @"data";
parameters[@"type"] = @"31";
parameters[@"maxtime"] = self.maxtime;
[[AFHTTPSessionManager manager] GET:XFJ_requestURL parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
self.maxtime = responseObject[@"info"][@"maxtime"];
NSArray *arrayTopics = [XFJItem mj_objectArrayWithKeyValuesArray:responseObject[@"list"]];
[self.item addObjectsFromArray:arrayTopics];
[responseObject writeToFile:@"/Users/xiaofeng/Desktop/New.plist" atomically:YES];
[self.tableView reloadData];
[self footerEndRefresh];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[self footerEndRefresh];
if (error.code == NSURLErrorCancelled) {
return ;
}
[SVProgressHUD showErrorWithStatus:@"网络繁忙,请稍后再试..."];
}];
});
}
- 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
—-> 3.2 加载最新的数据
#pragma mark - 加载最新的帖子数
- (void)setLoadNews
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
parameters[@"a"] = @"list";
parameters[@"c"] = @"data";
parameters[@"type"] = @"31";
[[AFHTTPSessionManager manager] GET:XFJ_requestURL parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
self.maxtime = responseObject[@"info"][@"maxtime"];
self.item = [XFJItem mj_objectArrayWithKeyValuesArray:responseObject[@"list"]];
[responseObject writeToFile:@"/Users/xiaofeng/Desktop/New1.plist" atomically:YES];
[self.tableView reloadData];
[self headerEndRefresh];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[self headerEndRefresh];
if (error.code == NSURLErrorCancelled) {
return ;
}
[SVProgressHUD showErrorWithStatus:@"网络繁忙,请稍后再试..."];
}];
});
}
- 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
五 模型
1 模型中的数据部分选择所有模块的公共部分作为属性
2 代码:
/**
* 踩(hate)
*/
@property (nonatomic, assign) NSInteger cai;
/**
* 顶(love)
*/
@property (nonatomic, assign) NSInteger love;
/**
* 帖子描述
*/
@property (nonatomic, strong) NSString *text;
/**
* 发帖时间
*/
@property (nonatomic, strong) NSString *passtime;
/**
* 用户名
*/
@property (nonatomic, strong) NSString *name;
/**
* 转发
*/
@property (nonatomic, assign) NSInteger repost;
/**
* 转发数
*/
@property (nonatomic, assign) NSInteger comment;
/**
* 头像
*/
@property (nonatomic, strong) NSString *profile_image;
- 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
六 添加尾部刷新控件
1 这里采用UILabel作为刷新的控件(也可以采用UIView)
2 注意刷新控件的添加位置(可以通过内部计算原理图来添加)
3 代码:
#pragma mark - 创建刷新的UILabel
- (void)setUpRefresh
{
UILabel *refreshLabel = [[UILabel alloc] init];
refreshLabel.text = @"上拉加载更多数据";
refreshLabel.backgroundColor = [UIColor redColor];
refreshLabel.textAlignment = NSTextAlignmentCenter;
refreshLabel.textColor = [UIColor whiteColor];
refreshLabel.XFJ_Height = 35;
self.tableView.tableFooterView = refreshLabel;
self.refreshLabel = refreshLabel;
[self setTitleRefresh];
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
七 底部刷新控件的业务逻辑
2 监听用户拖动的时候调用
#pragma mark - 代理方法(拖动的时候调用)
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[self dealFooter];
[self dealHeader];
}
3 处理用户往上拖拽的时候刷新条的业务逻辑
#pragma mark - footer处理尾部刷新拖动的时候逻辑
- (void)dealFooter
{
if (self.item.count == 0) return;
if (self.isFooterRefresh) return;
CGFloat offset = self.tableView.contentSize.height + self.tableView.contentInset.bottom - self.tableView.XFJ_Height;
if (self.tableView.contentOffset.y >= offset) {
[self footerBeginRefresh];
}
}
4 tableView开始刷新部分
#pragma mark - footer开始刷新
- (void)footerBeginRefresh
{
if (self.isFooterRefresh) return;
self.footerRefresh = YES;
self.refreshLabel.text = @"正在加载更多数据...";
self.refreshLabel.backgroundColor = [UIColor blueColor];
[self setUpMoreTopics];
}
5 tableView结束刷新部分
#pragma mark - footer结束刷新
- (void)footerEndRefresh
{
self.footerRefresh = NO;
self.refreshLabel.backgroundColor = [UIColor redColor];
self.refreshLabel.text = @"上拉加载更多数据";
}
八 顶部刷新控件的业务逻辑
1 创建顶部刷新条
2 注意添加的位置
3 代码部分:
#pragma mark - 创建下拉刷新控件
- (void)setTitleRefresh
{
UILabel *header = [[UILabel alloc] init];
header.backgroundColor = [UIColor redColor];
header.textColor = [UIColor whiteColor];
header.text = @"下拉加载跟多数据";
header.XFJ_Height = 50;
header.XFJ_Y = - header.XFJ_Height;
header.XFJ_Width = self.tableView.XFJ_Width;
[self.tableView addSubview:header];
header.textAlignment = NSTextAlignmentCenter;
self.header = header;
[self headerBeginRefresh];
}
- 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
4 监听用户往下拖动tableView,刷新内容的监听(使用代理方法)
—-> 4.1 用户停止拖动的时候调用
#pragma mark - 拖动停止的时候调用
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if (self.isHeaderRefresh) return;
CGFloat offset = - (self.tableView.contentInset.top + self.header.XFJ_Height);
if (self.tableView.contentOffset.y <= offset) {
[self headerBeginRefresh];
}
}
—-> 4.2 用户拖动的时候调用处理业务逻辑
#pragma mark - header处理头部逻辑
- (void)dealHeader
{
if (self.header == nil) return;
if (self.isHeaderRefresh) return;
CGFloat offsetInset = - (self.tableView.contentInset.top + self.header.XFJ_Height);
if (self.tableView.contentOffset.y <= offsetInset) {
self.header.text = @"松开立即刷新";
self.header.backgroundColor = [UIColor blueColor];
}else {
self.header.text = @"下拉可以刷新";
self.header.backgroundColor = [UIColor orangeColor];
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
4.3 顶部刷新条开始刷新
#pragma mark - header开始刷新
- (void)headerBeginRefresh
{
if (self.isHeaderRefresh) return;
self.headerRefresh = YES;
self.header.text = @"正在刷新数据...";
self.header.backgroundColor = [UIColor brownColor];
[UIView animateWithDuration:0.25 animations:^{
UIEdgeInsets offsetIns = self.tableView.contentInset;
offsetIns.top += self.header.XFJ_Height;
self.tableView.contentInset = offsetIns;
CGPoint offset = self.tableView.contentOffset;
offset.y = - offsetIns.top;
self.tableView.contentOffset = offset;
}];
[self setLoadNews];
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
4.4 顶部刷新条结束刷新
#pragma mark - header结束刷新
- (void)headerEndRefresh
{
self.headerRefresh = NO;
[UIView animateWithDuration:0.25 animations:^{
UIEdgeInsets offsetIns = self.tableView.contentInset;
offsetIns.top -= self.header.XFJ_Height;
self.tableView.contentInset = offsetIns;
}];
}
九 处理细节
1 程序一启动底部的刷新条会短暂的出现在顶部位置.
—-> 解决方案: 在tableView一刷新就会调用的方法中控制.(通过模型的数量老控制)
#pragma mark - 行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
self.refreshLabel.hidden = (self.item.count == 0);
return self.item.count;
}
2 程序开始启动的时候,自动刷新正常,但是当手动拖拽tableView进行刷新的时候,刷新的数量并不能控制,这是不合理的.(请求数据的时候控制了服务器返回的数据量)
—-> 解决方案: 通过定义一个第三方属性来记录状态,是否停止刷新和是否开始刷新.用if来做出判断.
十 刷新功能的追加模式(查看是否有数据重复)
1 通过查看写入的plist文件,查看到在maxtime中记录了每一次返回给客户端其参数的最后一个数字.比如:刷新的时候,接收到服务器的数据是50;49;48;47的时候,客户端在刷新完后,将47返回给服务器,然后服务器会根据接收到的请求参数,将位于47后面的信息返回给客户端,这样就达到了刷新的目的同时不会重复
2 有些公司是通过page来发送,来判断返回的数据是否重叠(不推荐使用,因为会照成错漏).
十一 知识点补充
1 我们是通过插入label的方式来实现刷新的目的,同理在很多app中会出现中间某些部位有广告弹出来,我们也可以往里面插入广告.
2 补充一些有关于宏的知识:
—-> 2.1 在宏里面,两个”##”的作用:链接两个标识符
#define method(name) - (void)load##name
method(abc) //- (void)loadabc
method(ddd) //- (void)loadddd
method(ttt) //- (void)loadttt
—-> 2.2 在宏里面,一个”#”的作用:给右边的标识符加上双引号.
#define test(name) @#name
test(abc) // @"abc"
十二 总结
1 该部分只是简单的tableView刷新部分,里面还有很多的不足,需要修改.作者里面表达的逻辑还是很容易明白的,只是我希望看过我这篇博客的人很有所收获,特别是要明白原理图.里面牵扯到了一些计算,不懂是没法做的.
2 最后,明天我将为大家继续完善百思不得姐app.如果大家觉得我写的博客还满意的话,麻烦大家关注我的官方博客,有什么问题,大家可以给我留言,我将一 一为大家解决,谢谢!!!!