刷新控件实现

刷新控件在项目中还是用的比较多的,可以依赖第三方框架做,但是如果自己的公司的刷新控件比较的特别,还是最好自己定制一个比较好,刷新分为上拉和下拉,实现起来都差不多,会了上拉,就只要改下刷新控件的3种状态变化的零界点和摆放位置,就可以实现上拉加载了。

如图所示下拉刷新的实现框架

下拉刷新.png

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<NSKeyValueChangeKey,id> *)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 <UIKit/UIKit.h>
#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];
        
        
    });
}];

推荐阅读更多精彩内容

  • 2016,悄然而逝。 如果不与时光负隅顽抗,我想将会有吞噬的危险。没有什么比时间更具有说服力了,因为时间无需通知我...
    榴莲姑娘_阅读 623评论 12 6
  • 我从初中开始就成了大胖子,每天打着上学压力大、辛苦、学校饭菜难吃的借口晚饭死吃猛吃,胖到巅峰的时候达到了150斤。...
    shine_泡泡阅读 246评论 0 6
  • 【人体穴位常识】 穴位是指神经末稍密集或神经干线经过的地方。穴位的学名是腧穴,别名包括:“气穴”、“气府”、“节”...
    燕荣姐姐阅读 3,011评论 0 18
  • 失了恋的米小米坐在我的对面,恨恨地喝下一杯啤酒,狠狠地嚼了几口肉串,如祥林嫂一般絮絮叨叨地说着她和那个肤浅、好色、...
    呵呵呵_3b28阅读 36评论 1 1