一.上拉刷新
1.为什么要做上拉刷新?
想要看一些旧的(更多)数据,就需要上拉刷新,加载更多数据
2.上拉刷新永远都显示在tableView最底部,用什么搭建?
tableFootView永远在tableView最底部,可以用它来搭建
3.上拉刷新业务逻辑
3.1当上拉刷新控件(footView)全部显示的时候,加载更多数据
3.2界面搭建
用xib根据自己需要搭建想要的样式
4.怎么判断上拉刷新控件完全显示?
4.1完全显示的条件是: 偏移量 = 内容高度 + 底部TabBar条高度 - 屏幕的高度
4.2通过scrollView的代理方法可以监听滚动,可以获得偏移量
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
4.3 当前偏移量 > = 偏移量的时候,上拉刷新控件就完全显示了
5.我们发现滚动条在最上面和最下面会被挡住一部分
5.1怎么解决?
设置一下滚动条的额外滚动区域就可以了
5.2怎么拿到这个属性?
去tableView头文件查找 UIEdgeInsets关键字,找不到
5.3去tableView的父控件scrollView中查找
找到 scrollIndicatorInsets属性,设置一下,发现就搞定了
6.上拉加载数据
6.1服务器返回的数据都有一个编号ID(自己的理解)
6.2编号ID是递增的,新的数据存到数据库,编号ID依次递增
6.3显示到界面的数据从上到下,编号ID递减,也就是,越下面,数据越早
6.4所以,我们只要拿到最下面一条数据的编号ID,请求这个编号之前的数据,就能拿到之前的数据了
6.5这个编号ID,服务器会给我们,我们只需要记录下来就可以了
6.6需要加载更多数据,只需要请求参数加上这个编号ID就可以了
7.bug:如果我们一直点击上拉刷新,会发送很多请求,导致数据重复,怎么解决?
7.1搞一个BOOL属性记录是否在加载更多数据,如果在加载,就不需要重复发送请求了
7.2这个属性记录在哪里?控制器?
记录在控制器不太好, 上拉刷新属于控件的业务逻辑,最好记录在控件内 加载的时候赋值为yes 加载完毕赋值为no
如果记录在控制器,如果其它地方用到上拉刷新,就需要把控制器也拖过去,耦合性太高
7.3 一开始运行,上拉刷新控件就会显示,怎么导致的?
一开始没有数据,上拉刷新会显示在tableView上,就会加载数据
7.4 怎么解决?
一开始先把footView隐藏,在第一次加载完数据,刷新表格之后,再显示
7.5 空间从xib加载出来,尺寸不对?
自动拉伸属性取消掉就可以了
8.根据是否完全显示,更改上拉刷新xib里面空间的内容
二.下拉刷新
1.为什么做下拉刷新?
用户想要看到最新的数据
2.下拉刷新,控件添加到哪里? headerView上?
不能添加到headerView 上, 一般headerView留给广告位
3.下拉刷新控件使用什么?
使用一个view , 设置view的y值为负数,就能显示在最上面,而且自带弹簧效果,把这个view添加到tableView上面
4.下拉控件业务逻辑
4.1 下拉控件在松手的时候,才需要刷新数据
4.2 拖动的时候,判断是否完全显示,完全显示,下拉控件的文字和箭头方向
5.下拉控件完全显示条件
5.1怎么判断下拉控件 完全显示?
也是用过偏移量(为负值) offsetY = - (导航条高度 + 下拉控件高度)
因为本来就有一个偏移量为导航条的高度
5.2 通过代理方法获取当前偏移量
当前偏移量 <= offsetY的时候,就完全显示
6.怎么修改下拉控件的文字和箭头方向
6.1 在控件中定义一个BOOL属性记录是否完全显示
6.2 在控制器中(代理方法中)判断是否完全显示,完全显示赋值为yes
6.3 连线拿到要改变得控件, 重写BOOL属性的set方法,在方法中修改文字和箭头方法
6.4 修改箭头方法用transform,正常情况设置负的角度(小于180)应该逆时针 ,但我们设置-180,发现为顺时针旋转??
苹果判断临界值,以最小的角度旋转,我们只需要在180上面加上一个很小的数值就可以了
7.上下拉冲突
7.1当网络比较慢,用户先上拉刷新,在下拉刷新就会有bug,会造成数据错乱,怎么解决?
7.2只需要在上拉刷新加载数据之前,把之前的所有的数据全部清除,始终保存最新的数据
7.3 假设网络比较慢 用户上拉之后,回来马上又下拉 原始数据为 51 50 49 48 47
上拉服务器应该返回数据 46 45 44 43 42
下拉服务器应该返回数据 53 52 51 50 49
最终服务器同时返回数据就会变成 53 52 51 50 49 46 45 44 43 42
数据就丢失了两条
7.4 怎么解决?
只允许同时发送一条请求
7.5 定义网络管理者对象,懒加载,在发送新的请求的时候,把之前的请求取消
// 取消之前请求
[self.mgr.tasks makeObjectsPerformSelector:@selector(cancel)];
8.什么时候需要刷新数据
8.1并不是一松手就要刷新数据
下拉控件完全显示的时候,松手才需要加载最新数据
8.2怎么监听松手?
代理方法:// 停止拖动
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
8.3正在请求最新数据的时候,不需要再发送请求数据了(一直拖拽下拉控件)
同样,在控件中也搞一个BOOL属性,记录是否正在加载数据
8.4刷新最新数据,一次有可能只有一条最新数据,
现有数据 50 49 48 47 46
加载数据 51 50 49 48 47
加载完数据排列 51 50 49 48 47 50 49 48 47 46
这样会造成数据重复
因为把数据转为模型后,遍历模型,把模型加到数组中,原来数组中就可能有这些模型了
8.5 解决数据重复
在加载新的数据之前,只需要把之前的数据全部清空就可以了
三.用第三方框架集成上下拉刷新
直接上源代码
- (void)setupRefreshView{
// 下拉刷新
// 当松手,并且下拉刷新完全显示的时候,就会触发下拉刷新
MJRefreshNormalHeader *header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewData)];
//下拉控件透明度自动变化(不拉的时候完全透明)
header.automaticallyChangeAlpha = YES;
self.tableView.mj_header = header;
// 上拉刷新
MJRefreshAutoNormalFooter *footer = [MJRefreshAutoNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)];
//上拉控件自动隐藏,没有数据的时候隐藏
footer.automaticallyHidden = YES;
self.tableView.mj_footer = footer;
}
注意:触发上下拉刷新,控件会一直存在,需要我们手动隐藏
在数据请求成功的时候隐藏
// 结束上拉刷新
[self.tableView.mj_footer endRefreshing];
// 结束下拉刷新
[self.tableView.mj_header endRefreshing];