iOS 下拉刷新-自定义

下拉刷新效果图

2d8378308241886d851cc34098d05490.gif
代码结构

//  XDRefreshView.h
//  XDRefreshView.m
//  XDRefreshView.h
//  下拉刷新-自定义
//
//  Created by 窦心东 on 16/9/24.
//  Copyright © 2016年 窦心东. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface XDRefreshView : UIView

@property (nonatomic ,copy) void(^refreshBlock)();
//结束刷新
- (void)endRefreshing;

@end
//
//  XDRefreshView.m
//  下拉刷新-自定义
//
//  Created by 窦心东 on 16/9/24.
//  Copyright © 2016年 窦心东. All rights reserved.
//

#import "XDRefreshView.h"
#define XDRefreshViewHeight 60
//三种状态
typedef enum{
    XDRefreshViewStatusNormol,  //正常状态
    XDRefreshViewStatusPuling,  //释放刷新状态
    XDRefreshViewStatusRefreshing   //正在刷新状态

} XDRefreshViewStatus;
@interface XDRefreshView ()

//图片
@property (nonatomic,strong) UIImageView *imageView;
//文字
@property (nonatomic,strong) UILabel *label;
//记录当前状态
@property (nonatomic,assign) XDRefreshViewStatus currenStatus;
//记录父控件,可以滚动的
@property (nonatomic,strong) UIScrollView *superScrollView;
//吃包子动画图片数组
@property (nonatomic,strong) NSArray *refreshImages;
@end

@implementation XDRefreshView

//添加子控件
-(instancetype)initWithFrame:(CGRect)frame{

    if (self=[super initWithFrame:frame]) {
        [self addSubview:self.imageView];
        [self addSubview:self.label];
        //设置frame
        self.imageView.frame = CGRectMake(80, 0, 50, 50);
        self.label.frame = CGRectMake(130, 20, 300, 20);
    }
    return self;
}
//监听父控件的滚动
//当控件加到父控件(tableview)时调用此方法
-(void)willMoveToSuperview:(UIView *)newSuperview{
    [super willMoveToSuperview:newSuperview];
//    NSLog(@"控件加到父控件是%@",newSuperview);//获取到父控件
    //父控件就是我们要监听滚动事件的父控件了
    //只有父控件能滚动的才能去监听
    if ([newSuperview isKindOfClass:[UIScrollView class]]) {
        self.superScrollView = (UIScrollView *)newSuperview;
        //监听父控件的滚动
        //当我们一直拖动tableView的时候scrollView有一个属性一直变化
        //所以说监听父控件的滚动就是监听 self.superScrollView对象的contentOffset的属性的改变
        //ios中用于监听对象属性的机制叫做KVO
        //          KVO: Key-Value-observing  键值监听
        //键值监听KVO作用:就是监听对象一个属性的改变
        //       KVO使用:我们要监听那个对象,就用哪个对象去调方法
        //当监听对象身上的这种属性发生变化时会[(addObserver)调用这个(forKeyPath:options:context:)方法]
        //注意⚠️使用KVO的时候,像使用通知一样需要用完取消在dealloc方法中
        [self.superScrollView addObserver:self forKeyPath:@"contentOffset" options:0 context:nil];
    }
}
#pragma mark - KVO时 当监听对象身上的这种属性发生变化时会调 用这个方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
//    NSLog(@"自己监听到父控件的滚动Y值:%f",self.superScrollView.contentOffset.y);
    //根据拖动的程度不同,来切换状态

    if (self.superScrollView.isDragging) {
        //手拖动normol->puling,puling->normol
        CGFloat normolPulingOffset = -124;
        if (self.currenStatus ==XDRefreshViewStatusPuling && self.superScrollView.contentOffset.y>normolPulingOffset) {
//            NSLog(@"切换到Normol");
            self.currenStatus = XDRefreshViewStatusNormol;
        }else if (self.currenStatus ==XDRefreshViewStatusNormol && self.superScrollView.contentOffset.y<=normolPulingOffset){
//            NSLog(@"切换到Puling");
            self.currenStatus = XDRefreshViewStatusPuling;
        }
    }else{
         //手松开puling->refreshing
        if (self.currenStatus ==XDRefreshViewStatusPuling) {
//            NSLog(@"切换到Refreshing");
            self.currenStatus = XDRefreshViewStatusRefreshing;
        }

    }
}
#pragma mark - 当切换状态时必经此方法getter
- (void)setCurrenStatus:(XDRefreshViewStatus)currenStatus{
    _currenStatus = currenStatus;
    switch (_currenStatus) {
        case XDRefreshViewStatusNormol:
        {
            NSLog(@"切换到Normol");
            //动画停下来
            [self.imageView stopAnimating];
            self.label.text = @"下拉刷新,再往下拖一点点";
            self.imageView.image = [UIImage imageNamed:@"normal"];
        }
            break;
        case XDRefreshViewStatusPuling:
        {
            NSLog(@"切换到Puling");
            self.label.text = @"释放我就可以刷新啦~~";
            self.imageView.image = [UIImage imageNamed:@"pulling"];
        }
            break;

        case XDRefreshViewStatusRefreshing:
        {
            NSLog(@"切换到Refreshing");
            NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
            [formatter setDateFormat:@"MM-dd-YY HH:mm"];
            NSString *timestamp = [formatter stringFromDate:[NSDate date]];
            self.label.text = [NSString stringWithFormat:@"数据最后更新时间%@",timestamp];
//            @"正在刷新数据哟......";
            self.imageView.animationImages = self.refreshImages;
            //播多长时间
            self.imageView.animationDuration = 0.1 * self.refreshImages.count;
            //开始播放
            [self.imageView startAnimating];
            //tableView往下走一点
            [UIView animateWithDuration:0.25 animations:^{
                self.superScrollView.contentInset = UIEdgeInsetsMake(self.superScrollView.contentInset.top+XDRefreshViewHeight, self.superScrollView.contentInset.left, self.superScrollView.contentInset.bottom, self.superScrollView.contentInset.right);
            }];
            //让控制器做事情
//            Block使用1.定义block 2.传递block3.调用block

            //3调用block 时先判断block是否有值,没有的话是会崩溃的
            if (self.refreshBlock) {
                self.refreshBlock();
            }
        }
            break;
            default:
            break;

    }

}
//结束刷新
- (void)endRefreshing{
    //refreshing->normol
    if (_currenStatus == XDRefreshViewStatusRefreshing) {
        self.currenStatus = XDRefreshViewStatusNormol;
        //tableView要回去
        [UIView animateWithDuration:0.25 animations:^{
            self.superScrollView.contentInset = UIEdgeInsetsMake(self.superScrollView.contentInset.top-XDRefreshViewHeight, self.superScrollView.contentInset.left, self.superScrollView.contentInset.bottom, self.superScrollView.contentInset.right);
        }];

    }




}
#pragma mark - deallco
-(void)dealloc{
    [self.superScrollView removeObserver:self forKeyPath:@"contentOffset" context:nil];
}
#pragma mark - 懒加载
-(UIImageView *)imageView{

    if (_imageView==nil) {
        UIImage *image = [UIImage imageNamed:@"normal"];
        _imageView = [[UIImageView alloc] initWithImage:image];

    }
    return  _imageView;
}
-(UILabel *)label{

    if (_label == nil) {
        _label = [[UILabel alloc] init];
        //设置
        _label.textColor = [UIColor darkGrayColor];
        _label.font = [UIFont systemFontOfSize:16];
        _label.text = @"下拉刷新";
    }
    return _label;
}
-(NSArray *)refreshImages{
    if (_refreshImages==nil) {
        NSMutableArray *arrayM = [NSMutableArray array];
        for (int i=1; i<4; i++) {
            NSString *imagesName = [NSString stringWithFormat:@"refreshing_0%d",i];
            UIImage *image = [UIImage imageNamed:imagesName];
            [arrayM addObject:image];
        }
        _refreshImages = arrayM;
    }
    return _refreshImages;
}

@end
//  XDRefreshTableViewController.h
//  XDRefreshTableViewController.m

//
//  XDRefreshTableViewController.h
//  下拉刷新-自定义
//
//  Created by 窦心东 on 16/9/24.
//  Copyright © 2016年 窦心东. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface XDRefreshTableViewController : UITableViewController

@end
//
//  XDRefreshTableViewController.m
//  下拉刷新-自定义
//
//  Created by 窦心东 on 16/9/24.
//  Copyright © 2016年 窦心东. All rights reserved.
//

#import "XDRefreshTableViewController.h"
#import "XDRefreshView.h"
@interface XDRefreshTableViewController ()
//要显示的数据
@property (nonatomic,strong) NSArray *cities;
@property (nonatomic,strong) XDRefreshView *refreahView;
@end

@implementation XDRefreshTableViewController
/**
 * 创建下拉刷新控件
 */
-(XDRefreshView *)refreahView{

    if (_refreahView==nil) {
        _refreahView = [[XDRefreshView alloc] initWithFrame:CGRectMake(0,-60, [UIScreen mainScreen].bounds.size.width, 60)];
//        _refreahView.backgroundColor = [UIColor brownColor];
    }
    return _refreahView;
}
- (void)viewDidLoad {
    [super viewDidLoad];

    /**
     *  加载数据
     */
    self.cities = [self loadData];
    //添加刷新控件到tableView上
    [self.tableView addSubview:self.refreahView];
    //1定义block  : refreahView.refreshBlock
    //2传递block(赋值):refreahView.refreshBlock = ^()
    self.refreahView.refreshBlock = ^(){
        NSLog(@"告诉控制器进入刷新状态了");
        //由于加载的是plist文件比较快,现在我们用GCD方式添加延时
        ino64_t delayInSeconds = 3;
        __weak XDRefreshTableViewController *weakSelf = self;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            //加载数据
            NSArray *newArray = [weakSelf loadData];
            NSMutableArray *newArrayM = [NSMutableArray arrayWithArray:newArray];
            [newArrayM addObjectsFromArray:weakSelf.cities];
            weakSelf.cities = newArrayM;
            [weakSelf.tableView reloadData];
            //结束刷新
            [weakSelf.refreahView endRefreshing];
        });

    };

}
-(void)viewDidAppear:(BOOL)animated{

    [super viewDidAppear:animated];
    NSLog(@"self.tableView.contentInset.top(tableView的起始位置Y值) =%f",self.tableView.contentInset.top);
}
//加载数据源数据
- (NSArray *)loadData{
    NSString *path = [[NSBundle mainBundle] pathForResource:@"cities" ofType:@"plist"];
    NSArray *array = [NSArray arrayWithContentsOfFile:path];
    return array;
}

#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    return self.cities.count;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"reuseIdentifier" forIndexPath:indexPath];
    cell.textLabel.text = self.cities[indexPath.row];
    return cell;
}



@end

效果图

2d8378308241886d851cc34098d05490.gif

项目地址:https://github.com/douxindong/XDRefresh.git

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值