给UIView添加一个类目,用来快速获得控件的一些尺寸
//
// UIView+Frame.h
// PDBuDeJie
//
// Created by 裴铎 on 2018/6/8.
// Copyright © 2018年 裴铎. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIView (Frame)
/**
宽
*/
@property CGFloat pd_width;
/**
高
*/
@property CGFloat pd_height;
/**
X轴
*/
@property CGFloat pd_x;
/**
Y轴
*/
@property CGFloat pd_y;
/**
中心X轴
*/
@property CGFloat pd_centerX;
/**
中心Y轴
*/
@property CGFloat pd_centerY;
@end
//
// UIView+Frame.m
// PDBuDeJie
//
// Created by 裴铎 on 2018/6/8.
// Copyright © 2018年 裴铎. All rights reserved.
//
#import "UIView+Frame.h"
@implementation UIView (Frame)
- (void)setPd_width:(CGFloat)pd_width{
CGRect rect = self.frame;
rect.size.width = pd_width;
self.frame = rect;
}
- (CGFloat)pd_width{
return self.frame.size.width;
}
- (void)setPd_height:(CGFloat)pd_height{
CGRect rect = self.frame;
rect.size.height = pd_height;
self.frame = rect;
}
- (CGFloat)pd_height{
return self.frame.size.height;
}
- (void)setPd_x:(CGFloat)pd_x{
CGRect rect = self.frame;
rect.origin.x = pd_x;
self.frame = rect;
}
- (CGFloat)pd_x{
return self.frame.origin.x;
}
- (void)setPd_y:(CGFloat)pd_y{
CGRect rect = self.frame;
rect.origin.y = pd_y;
self.frame = rect;
}
- (CGFloat)pd_y{
return self.frame.origin.y;
}
- (void)setPd_centerX:(CGFloat)pd_centerX{
CGPoint center = self.center;
center.x = pd_centerX;
self.center = center;
}
- (CGFloat)pd_centerX{
return self.center.x;
}
- (void)setPd_centerY:(CGFloat)pd_centerY{
CGPoint center = self.center;
center.y = pd_centerY;
self.center = center;
}
- (CGFloat)pd_centerY{
return self.center.y;
}
@end
初始化上下拉刷新控件
- (void)setupRefresh{
//加载头部广告视图
//[self setupADView];
//下啦刷新视图
UIView * headerView = [[UIView alloc] init];
//很多的应用tableView头部都会添加广告,所以 Y -50 让出广告位
headerView.frame = CGRectMake(0, - 50, self.tableView.pd_width, 50);
//赋值给全局属性
self.headerView = headerView;
UILabel * headerLabel = [[UILabel alloc] init];
headerLabel.frame = headerView.bounds;
headerLabel.backgroundColor = [UIColor grayColor];
headerLabel.text = @"下拉加载更多";
headerLabel.textAlignment = NSTextAlignmentCenter;
self.headerLabel = headerLabel;
[self.headerView addSubview:self.headerLabel];
//把下啦刷新的视图添加到tableView的子视图,这样不会影响tableView的contentSize
[self.tableView addSubview:self.headerView];
//上拉刷新
UIView * footerView = [[UIView alloc] init];
footerView.frame = CGRectMake(0, 0, self.tableView.pd_width, 35);
self.footerView = footerView;
UILabel * footerLabel = [[UILabel alloc] init];
footerLabel.frame = footerView.bounds;
footerLabel.backgroundColor = [UIColor grayColor];
footerLabel.text = @"上拉加载更多";
footerLabel.textAlignment = NSTextAlignmentCenter;
self.footerLabel = footerLabel;
[self.footerView addSubview:self.footerLabel];
self.tableView.tableFooterView = self.footerView;
}
当滚动视图结束减速时触发
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
CGFloat offsetY = - (self.tableView.contentInset.top + self.headerView.pd_height + 64);
if (self.tableView.contentOffset.y <= offsetY) {
//进入刷新状态
[self headerBeginRefreshing];
}
}
只要滚动了就调用头尾的刷新方法,在刷新方法内判断滚动到哪里了,是否开始刷新
因为应用内有全屏穿透效果,所以头部的下拉刷新控件默认时隐藏的,当向下拖拽到一定位置才会出现
//只要进行滚动就触发的代理方法,
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
//处理header下拉刷新
[self dealHeader];
//处理footer上拉刷新
[self dealFooter];
//当tableView向下拖拽的时候,显示提示标题
if (self.tableView.contentOffset.y < -99) {
//当视图滚动到一定的位置显示下拉刷新提示label
self.headerLabel.hidden = NO;
}else{
self.headerLabel.hidden = YES;
}
}
处理上下刷新的方法,内部判断滚动的位置,和是否应该刷新
/**
处理header
*/
- (void)dealHeader{
//正在进行下啦刷新
//定义布尔型变量用来判断是否正在刷新
if (self.isHeaderRefreshing) return;
//当前滚动的偏移量 <= offsetY时,证明tableView下啦刷新控件已经完全出现了
CGFloat offsetY = - (self.tableView.contentInset.top + self.headerView.pd_height + 64);
if (self.tableView.contentOffset.y <= offsetY) {
self.headerLabel.text = @"松开立即刷新";
}else{
self.headerLabel.text = @"下拉加载新鲜事.";
self.headerLabel.backgroundColor = [UIColor grayColor];
}
}
/**
处理footer
*/
- (void)dealFooter{
//如果当前tableview的内容没有加载完成就返回,防止出现tableView内没有内容,尾部的刷新直接触发了
if (self.tableView.contentSize.height == 0) {
return;
}
//判断如果正在刷新就返回,防止重复刷新
if (self.isFooterRefreshing) return;
//当前滚动的偏移量 > offsetY时,证明tableView的内容已经滚动完成了
CGFloat offsetY = self.tableView.contentSize.height - self.tableView.pd_height + 49;
if (self.tableView.contentOffset.y >= offsetY && self.tableView.contentOffset.y > - 90) {
//进入刷新
[self footerBeginRefreshing];
}
}
用来给头部和尾部调用的请求数据的方法
#pragma mark - 数据处理
/**
* 发送请求给服务器,下拉刷新数据
*/
- (void)loadNewTopics{
//创建AFN管理器对象
AFHTTPSessionManager * manager = [AFHTTPSessionManager manager];
//设置AFN的解析器类型 默认是JSON的解析器,如果解析JSON可以不写这个
manager.responseSerializer = [[AFJSONResponseSerializer alloc] init];
//拼接参数
NSMutableDictionary * parameters = [NSMutableDictionary dictionary];
//给网络请求的每一个参数 赋值 parameters[@"key"] = @"value";
parameters[@"key"] = @"value";
/**
参数
1./URL
2./请求参数
3./获得下载进度
4./请求成功执行的代码块 代码block块都是在主线程执行
5./请求失败执行的代码块
*/
[manager GET:PDPublicURL parameters:parameters progress:^(NSProgress * _Nonnull downloadProgress) {
//下载进度
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
//下载成功
NSLog(@"%@",responseObject);
//回到主线程刷新UI界面
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
//结束刷新
[self headerEndRefreshing];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
//下载失败
[SVProgressHUD showErrorWithStatus:@"网络繁忙,请稍后再试."];
//结束刷新
[self headerEndRefreshing];
}];
}
/**
* 发送请求给服务器,上拉加载更多数据
*/
- (void)loadMoreTopics{
//创建AFN管理器对象
AFHTTPSessionManager * manager = [AFHTTPSessionManager manager];
//设置AFN的解析器类型 默认是JSON的解析器,如果解析JSON可以不写这个
manager.responseSerializer = [[AFJSONResponseSerializer alloc] init];
//拼接参数
NSMutableDictionary * parameters = [NSMutableDictionary dictionary];
//给网络请求的每一个参数 赋值 parameters[@"key"] = @"value";
parameters[@"key"] = @"value";
/**
参数
1./URL
2./请求参数
3./获得下载进度
4./请求成功执行的代码块 代码block块都是在主线程执行
5./请求失败执行的代码块
*/
[manager GET:PDPublicURL parameters:parameters progress:^(NSProgress * _Nonnull downloadProgress) {
//下载进度
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
//下载成功
NSLog(@"%@",responseObject);
//回到主线程刷新UI界面
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
//结束刷新
[self footerEndRefreshing];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
//下载失败
[SVProgressHUD showErrorWithStatus:@"网络繁忙,请稍后再试."];
//结束刷新
[self footerEndRefreshing];
}];
}
头部和尾部开始刷新的方法,开始刷新内部必须调用结束刷新方法
#pragma mark - header开始刷新
- (void)headerBeginRefreshing
{
// 如果正在下拉刷新,直接返回
if (self.isHeaderRefreshing) return;
// 如果正在上拉刷新,直接返回
if (self.isFooterRefreshing) return;
// 进入下拉刷新状态
self.headerLabel.text = @"正在刷新数据...";
self.headerLabel.backgroundColor = [UIColor blueColor];
self.headerRefreshing = YES;
// 增加内边距
[UIView animateWithDuration:0.3 animations:^{
UIEdgeInsets inset = self.tableView.contentInset;
inset.top = 85;
self.tableView.contentInset = inset;
}];
// 修改偏移量 让tableView回到顶部刷新所有数据
self.tableView.contentOffset = CGPointMake(self.tableView.contentOffset.x, - 149);
// 发送请求给服务器,下拉刷新数据
[self loadNewTopics];
}
- (void)headerEndRefreshing
{
self.headerRefreshing = NO;
// 减小内边距
[UIView animateWithDuration:0.2 animations:^{
UIEdgeInsets inset = self.tableView.contentInset;
inset.top = 35;
self.tableView.contentInset = inset;
self.headerLabel.hidden = YES;
}];
}
#pragma mark - footer开始刷新
- (void)footerBeginRefreshing
{
// 如果正在上拉刷新,直接返回
if (self.isFooterRefreshing) return;
// 如果正在下拉刷新,直接返回
if (self.isHeaderRefreshing) return;
// 进入刷新状态
self.footerRefreshing = YES;
self.footerLabel.text = @"正在加载更多数据...";
// 发送请求给服务器,上拉加载更多数据
[self loadMoreTopics];
}
- (void)footerEndRefreshing
{
//结束刷新后将显示标签和bool变量变会初始状态
self.footerRefreshing = NO;
self.footerLabel.text = @"上拉可以加载更多";
}