刷新控件在项目中还是用的比较多的,可以依赖第三方框架做,但是如果自己的公司的刷新控件比较的特别,还是最好自己定制一个比较好,刷新分为上拉和下拉,实现起来都差不多,会了上拉,就只要改下刷新控件的3种状态变化的零界点和摆放位置,就可以实现上拉加载了。
如图所示下拉刷新的实现框架
1.刷新的3种状态
先写一个emun,用来表示下刷新的3种状态
typedef NS_ENUM(NSInteger, Status) {
StatusNormal, //正常状态
StatusPulling, //释放刷新状态
StatusRefreshing //正在刷新状态
};
2.初始化下拉刷新控件
2.1初始化下拉刷新控件
static CGFloat const headerHeight = 60;
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, headerHeight);
self.backgroundColor = [UIColor whiteColor];
//添加子控件
[self addSubview:self.animView];
[self addSubview:self.title];
for (UIView *view in self.subviews) {
view.translatesAutoresizingMaskIntoConstraints = NO;
}
//添加约束
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.animView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1 constant:-5]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.animView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
//text
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.title attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1 constant:5]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.title attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
}
return self;
}
2.2 willMoveToSuperview找到父控件监听属性
- (void)willMoveToSuperview:(UIView *)newSuperview{
[super willMoveToSuperview:newSuperview];
if ([newSuperview isKindOfClass:[UIScrollView class]]) {
self.scrollView = (UIScrollView *)newSuperview;
//监听tableView的contentSize contentOffset
[self.scrollView addObserver:self forKeyPath:@"contentSize" options:0 context:NULL];
[self.scrollView addObserver:self forKeyPath:@"contentOffset" options:0 context:NULL];
}
}
3 利用kvo监听Scrollview属性
3.1在KVO中完成对属性的监听
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
//调整frame
if ([keyPath isEqualToString:@"contentSize"]) {
CGRect frame = self.frame;
frame.origin.y = - headerHeight;
self.frame = frame;
//调整刷新控件的状态
}else if ([keyPath isEqualToString:@"contentOffset"])
{
if (self.scrollView.isDragging) { //拖动
if(self.scrollView.contentOffset.y > -headerHeight - 64)
{
self.status = StatusNormal;
}else if((self.scrollView.contentOffset.y <= -headerHeight - 64) && self.status == ZHPullDownHeaderViewStatusNormal) //当footerview完全显示并且,刷新控件的状态是normal时候才要改变状态
{
self.status = StatusPulling;
}
}else
{
//停止刷新,pulling -> refershing
if(self.status == StatusPulling)
{
self.status = StatusRefreshing;
}
}
}
}
3.2刷新控件的状态处理
根据刷新控件的状态变化,对刷新控件上的控件进行设置
- (void)setStatus:(Status)status
{
_status = status;
switch (_status) {
case StatusNormal:
self.title.text = @"下拉刷新数据";
self.animView.image = [UIImage imageNamed:@"normal"];
break;
case StatusPulling:
self.title.text = @"释放刷新";
self.animView.image = [UIImage imageNamed:@"pulling"];
break;
case StatusRefreshing:
{
self.title.text = @"正在刷新数据...";
//动画view
self.animView.animationImages = self.refershImages;
self.animView.animationDuration = self.refershImages.count * 0.1;
[self.animView startAnimating];
UIEdgeInsets contentInset = self.scrollView.contentInset;
contentInset.top = contentInset.top + headerHeight;
self.scrollView.contentInset = contentInset;
[UIView animateWithDuration:0.25 animations:^{
self.scrollView.contentInset = contentInset;
} completion:^(BOOL finished) {
//让控制器加载数据
if ((self.headerRefersh)) {
self.headerRefersh();
}
}];
}
break;
default:
break;
}
}
3.3 停止刷新
- (void)endRefershing
{
if (self.status == StatusRefreshing) {
[self.animView stopAnimating];
UIEdgeInsets contentInset = self.scrollView.contentInset;
contentInset.top = contentInset.top - headerHeight;
self.scrollView.contentInset = contentInset;
self.status = StatusNormal;
}
}
4.delloc方法中移除监听
使用NSNotification不移除监听者,会出现内存泄漏,使用kvo不移除,程序会崩溃!!!
- (void)dealloc
{
//移除KVO的监听
[self.scrollView removeObserver:self forKeyPath:@"contentSize"];
[self.scrollView removeObserver:self forKeyPath:@"contentOffset"];
}
5.为方便使用为scrollview添加分类
在UIScrollView+Refersh.h中
#import
#import "HeaderView.h"
@interface UIScrollView (Refersh)
@property (nonatomic, strong) HeaderView *headerView;
@end
在UIScrollView+Refersh.m中
static const char *headerViewKey = "headerViewKey";
- (void)setHeaderView:(HeaderView *)headerView
{
objc_setAssociatedObject(self, headerViewKey, headerView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (ZHPullDownHeaderView *)headerView
{
ZHPullDownHeaderView *headerView = objc_getAssociatedObject(self, headerViewKey);
//防止获取到为空
if (!headerView) {
headerView = [[HeaderView alloc] init];
[self addSubview:headerView];
self.headerView = headerView;
}
return headerView;
}
6.使用
[self.tableView.headerView setHeaderRefersh:^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[weakSwlf.tableView.headerView endRefershing];
for (int i=0; i< 15; i++) {
[weakSwlf.dataList insertObject:[NSString stringWithFormat:@"插入数据%d",i] atIndex:0];
}
[weakSwlf.tableView reloadData];
});
}];