一 刷新功能图和内部计算原理图
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) {
//取出info中的maxtime
self.maxtime = responseObject[@"info"][@"maxtime"];
//字典数组转模型数组(装入可变数组中)
NSArray *arrayTopics = [XFJItem mj_objectArrayWithKeyValuesArray:responseObject[@"list"]];
//将模型添加到装数组的模型中
[self.item addObjectsFromArray:arrayTopics];
//写入plist文件
[responseObject writeToFile:@"/Users/xiaofeng/Desktop/New.plist" atomically:YES];
//刷新tableView
[self.tableView reloadData];
//尾部结束刷新
[self footerEndRefresh];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
//尾部刷新数据失败也需要调用
[self footerEndRefresh];
//如果用户直接取消任务,来到failure中不需要提醒信息
if (error.code == NSURLErrorCancelled) {
return ;
}
//提醒用户刷新失败
[SVProgressHUD showErrorWithStatus:@"网络繁忙,请稍后再试..."];
}];
});
}
—-> 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) {
//取出info中的maxtime
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];
//如果用户直接取消任务,来到failure中不需要提醒信息
if (error.code == NSURLErrorCancelled) {
return ;
}
//提醒用户刷新失败
[SVProgressHUD showErrorWithStatus:@"网络繁忙,请稍后再试..."];
}];
});
}
五 模型
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 这里采用UILabel作为刷新的控件(也可以采用UIView)
2 注意刷新控件的添加位置(可以通过内部计算原理图来添加)
3 代码:
#pragma mark - 创建刷新的UILabel
- (void)setUpRefresh
{
//上拉刷新控件
//创建Label
UILabel *refreshLabel = [[UILabel alloc] init];
//设置label文字
refreshLabel.text = @"上拉加载更多数据";
//设置颜色
refreshLabel.backgroundColor = [UIColor redColor];
//设置文字的位置
refreshLabel.textAlignment = NSTextAlignmentCenter;
//设置文字颜色
refreshLabel.textColor = [UIColor whiteColor];
//设置高度
refreshLabel.XFJ_Height = 35;
//添加到footerView
self.tableView.tableFooterView = refreshLabel;
//赋值
self.refreshLabel = refreshLabel;
//下拉刷新控件
[self setTitleRefresh];
}
七 底部刷新控件的业务逻辑
1 由于我们需要时刻的监听用户拖拽tableView的时候,来显示刷新控件的显示状态.因为UITableView是继承UIScrollView的,所以也同时拥有了UIScrollView中的方法.
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;
//修改label文字
self.refreshLabel.text = @"正在加载更多数据...";
//修改label背景颜色
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
{
//创建label
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];
}
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
{
//如果header还没有被创建的话就直接返回
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];
}
}
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];
}
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
{
//隐藏开始启动程序的label的片刻出现
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.如果大家觉得我写的博客还满意的话,麻烦大家关注我的官方博客,有什么问题,大家可以给我留言,我将一 一为大家解决,谢谢!!!!
时间: 2024-10-11 10:42:02