因项目会使用到TableView和CollectionView上拉下拉的功能,但又不想引用到三方的一大堆SDK,就仿着其功能,做了一个简易的封装。
下面主要以介绍TableView上拉下拉实现为主,CollectionView的实现和TableView原理一模一样。
原理:
监听TableView和CollectionView的服类UIScrollView里的属性contentOffset改变,根据contentOffset的值做判断。
核心代码:
[self addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
//监听UITableview的顶部和头部下拉事件
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
if ([keyPath isEqualToString:@"contentOffset"] && !self.isLoading && !self.isRefreshing) {
self.refreshHeaderView.frame = CGRectMake(0, -self.changeTopHeight, self.frame.size.width, self.changeTopHeight);
self.loadingFooterView.frame = CGRectMake(0, self.contentSize.height, self.frame.size.width, self.changeFootHeight);
float height = self.contentSize.height > self.frame.size.height ?self.frame.size.height : self.contentSize.height;
if (self.isDragging) {
if (- self.contentOffset.y > self.changeTopHeight && self.didBeginRefreshBlock) {
// 调用下拉刷新方法
self.canRefech = YES;
[self.refreshHeaderView setRefreshMode:2];
}else{
self.canRefech = NO;
[self.refreshHeaderView setRefreshMode:-1];
}
if(self.isNoData && self.didBeginLoadingBlock){
self.canLoding = NO;
[self.loadingFooterView setLoadingMode:3];
}else{
if ((height - self.contentSize.height + self.contentOffset.y) > self.changeFootHeight && self.didBeginLoadingBlock) {
// 调用上拉加载方法
self.canLoding = YES;
[self.loadingFooterView setLoadingMode:4];
}else{
self.canLoding = NO;
[self.loadingFooterView setLoadingMode:-1];
}
}
}
else
{
if ((- self.contentOffset.y > self.changeTopHeight) && self.canRefech && self.didBeginRefreshBlock)
{
self.drageMode = 1;
self.canRefech = NO;
[self beginRefresh];
}
else if (((height - self.contentSize.height + self.contentOffset.y) > self.changeFootHeight) && self.canLoding && self.didBeginLoadingBlock)
{
self.drageMode = 2;
self.canLoding = NO;
if(!self.isNoData){
[self beginLoading];
}
}
}
}
}
因为是对UIScrollView做的监听判断,所以TableView和CollectionView该方法通用,并且不会影响其原有功能。
使用:
初始化:
初始化时和正常的TableView并无两样,当你需要上拉下拉功能,就添加上拉下拉事件的回调,不添对应回调,则此TableView不会触发对应事件
MyTableViewLoadingInfo * showInfo = [[MyTableViewLoadingInfo alloc]initWithbeginLoadingText:@"加载中" willLodingText:@"松开加载" endLoadingText:@"加载完毕" noDayaText:@"暂无更多数据" beginRefreshText:@"下拉刷新" willRefreshText:@"松开刷新" endRefreshText:@"正在刷新"];//自定义提示信息
MyTableView * tableView = [[MyTableView alloc]initWithFrame:CGRectMake(0, 0, 100, 200) style:UITableViewStylePlain showInfo:showInfo];
//MyTableView * tableView = [[MyTableView alloc]initWithFrame:CGRectMake(0, 0, 100, 200) style:UITableViewStylePlain];//使用默认提示
tableView.delegate = self;
tableView.dataSource = self;
[tableView whenBeginRefresh:^{
NSLog(@"开始刷新");
}];
[tableView whenBeginLoading:^{
NSLog(@"开始加载");
}];
结束操作:
当上拉下拉触发时,会自动进行动画展示,当数据请求完后,可以通知TableView结束操作。
//结束加载动画
[tableView endLoading];
//结束刷新动画
[tableView endRefresh];
//结束加载动画,并展示无更多数据(此后无法触发加载事件,重新刷新后可触发)
[tableView nodata];
分页功能:
一般上拉下拉都会涉及到分页,为了方便分页功能,我在封装的TableView加入了一些属性。
//MyTableView
@property(nonatomic,readwrite)int pageIndex;//当前页码 默认0
@property(nonatomic,readwrite)int pageSize;//页码大小 默认10
//MyTableView
//使用
-(void)loadNetData:(BOOL)isRefrsh {
if(isRefrsh){
self.tableView.pageIndex = 1;
[self.datas removeAllObjects];
}else{
self.tableView.pageIndex ++;
}
[NetWorkManager SearchListPageNo:self.tableView.pageIndex pageSize:self.tableView.pageSize succeedBlock:^(ListPostRes * _Nonnull res) {
[self.datas addObjectsFromArray:res.postInfoArray];
if(isRefrsh){
[self.tableView endRefresh];
}
if(res.total <= self.datas.count){
[self.tableView nodata];
}else if(!isRefrsh){
[self.tableView endLoading];
}
[self.tableView reloadData];
} failBlock:^(NSString * _Nonnull errorstr) {
[self.tableView endRefresh];
[self.tableView endLoading];
}];
}
功能触发边界高度值
考虑到一般TableView上拉和下拉的触发高度值都不一样,所以这里定义了两个属性
@property(nonatomic, assign)CGFloat changeTopHeight;//偏移多少触发下拉刷新 默认80
@property(nonatomic, assign)CGFloat changeFootHeight;//偏移多少触发上拉加载 默认60
下载
下面是我封装好的文件,可以参考
联系作者
期待你的点赞和关注!如有疑问,联系作者。