IOS UITableView下拉刷新和上拉加载功能的实现

  在IOS开发中UITableView是非常常用的一个功能,而在使用UITableView的时候我们经常要用到下拉刷新和上拉加载的功能,今天花时间实现了简单的UITableView的下拉刷新和上拉加载功能,效果图如下:

 

  代码如下:

TableRefreshHeaderView.h

#import <UIKit/UIKit.h>

@interface TableRefreshHeaderView : UIView

@property(nonatomic, strong)UIImageView *arrowView;

@property(nonatomic, strong)UILabel *refreshText;

@property(nonatomic, strong)UIActivityIndicatorView *loadingIndicatorView;

-(instancetype)initWithFrame:(CGRect)frame;

- (void)setRefreshMode:(int)mode;

@end

TableRefreshHeaderView.m

#import "TableRefreshHeaderView.h"

#define UISCREEN_WIDTH [UIScreen mainScreen ].bounds.size.width
#define UISCREEN_HEIGHT [UIScreen mainScreen ].bounds.size.height

@implementation TableRefreshHeaderView

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

-(instancetype)initWithFrame:(CGRect)frame;
{
    self = [super initWithFrame:frame];
    if (self) {
        [self addSubview:self.arrowView];
        [self addSubview:self.refreshText];
        [self addSubview:self.loadingIndicatorView];
        self.loadingIndicatorView.hidden = YES;
    }
    return self;
    
}

//箭头图片UIImageView
-(UIImageView *)arrowView
{
    if (!_arrowView) {
        _arrowView = [[UIImageView alloc]initWithFrame:CGRectMake(UISCREEN_WIDTH / 2.0 - 60, 0, 15, 30)];
        _arrowView.image = [UIImage imageNamed:@"arrow"];
    }
    return _arrowView;
}

//下拉刷新文字
-(UILabel *)refreshText
{
    if (!_refreshText) {
        _refreshText = [[UILabel alloc]initWithFrame:CGRectMake(UISCREEN_WIDTH / 2.0 - 15, 0, 75, 30)];
        _refreshText.font = [UIFont fontWithName:@"Arial" size:14];
        _refreshText.textColor = [UIColor blackColor];
        _refreshText.text = @"下拉刷新";
    }
    return _refreshText;
}

//刷新旋转视图
- (UIActivityIndicatorView *)loadingIndicatorView
{
    if (!_loadingIndicatorView) {
        _loadingIndicatorView = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(UISCREEN_WIDTH / 2.0 - 65, 2, 25, 25)];
        [_loadingIndicatorView setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
        _loadingIndicatorView.backgroundColor = [UIColor clearColor];
        _loadingIndicatorView.center = CGPointMake(UISCREEN_WIDTH / 2.0 - 52, 14);
    }
    return _loadingIndicatorView;
}

//设置三种刷新模式
- (void)setRefreshMode:(int)mode
{
    switch (mode) {
        case 1://下拉过程中
        {
            self.arrowView.hidden = NO;
            self.loadingIndicatorView.hidden = YES;
            [self.loadingIndicatorView stopAnimating];
            [UIView animateWithDuration:0.3 animations:^(void){
                _arrowView.transform = CGAffineTransformMakeRotation(M_PI * 2);
            }];
            self.refreshText.text = @"下拉刷新";
        }
            break;
        case 2://提示松开刷新
        {
            self.arrowView.hidden = NO;
            self.loadingIndicatorView.hidden = YES;
            [self.loadingIndicatorView stopAnimating];
            [UIView animateWithDuration:0.3 animations:^(void){
                _arrowView.transform = CGAffineTransformMakeRotation(M_PI);
            }];
            self.refreshText.text = @"松开刷新";
        }
            break;
        case 3://松开后刷新
        {
            self.arrowView.hidden = YES;
            self.loadingIndicatorView.hidden = NO;
            [self.loadingIndicatorView startAnimating];
            self.refreshText.text = @"正在刷新";
            
        }
            break;
            
        default:
            break;
    }
}


@end

TableRefreshFooterView.h

#import <UIKit/UIKit.h>

@interface TableRefreshFooterView : UIView

@property(nonatomic, strong) UIActivityIndicatorView *loadingIndcatorView;

@property(nonatomic, strong) UILabel *loadingText;

- (void)setLoadingMode:(int)mode;

@end

TableRefreshFooterView.m

#import "TableRefreshFooterView.h"

#define UISCREEN_WIDTH [UIScreen mainScreen ].bounds.size.width
#define UISCREEN_HEIGHT [UIScreen mainScreen ].bounds.size.height

@implementation TableRefreshFooterView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self addSubview:self.loadingIndcatorView];
        [self addSubview:self.loadingText];
    }
    return self;
}

- (UIActivityIndicatorView *)loadingIndcatorView
{
    if (!_loadingIndcatorView) {
        _loadingIndcatorView = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(UISCREEN_WIDTH / 2.0 - 65, 2, 25, 25)];
        [_loadingIndcatorView setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
        _loadingIndcatorView.backgroundColor = [UIColor clearColor];
        _loadingIndcatorView.center = CGPointMake(UISCREEN_WIDTH / 2.0 - 52, 14);
    }
    return _loadingIndcatorView;
}

- (UILabel *)loadingText
{
    if (!_loadingText) {
        _loadingText = [[UILabel alloc]initWithFrame:CGRectMake(UISCREEN_WIDTH / 2.0 - 15, 0, 75, 30)];
        _loadingText.font = [UIFont fontWithName:@"Arial" size:14];
        _loadingText.textColor = [UIColor blackColor];
        _loadingText.text = @"加载中";
    }
    return _loadingText;
}

- (void)setLoadingMode:(int)mode
{
    switch (mode) {
        case 1:
            _loadingText.text = @"加载中";
            [self.loadingIndcatorView startAnimating];
            self.loadingIndcatorView.hidden = NO;
            break;
            case 2:
            _loadingText.text = @"加载完毕";
            [self.loadingIndcatorView stopAnimating];
            self.loadingIndcatorView.hidden = YES;
            break;
        default:
            break;
    }
}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/



@end

ViewController.h

#import <UIKit/UIKit.h>
#import "TableRefreshHeaderView.h"
#import "TableRefreshFooterView.h"

@interface ViewController : UIViewController<UITableViewDelegate, UITableViewDataSource>
{
    int rowCount;//行数
    BOOL isLoading;//是否正在加载
    BOOL isRefreshing;//是否正在刷新
    int drageMode;//1为下拉刷新,2为上拉加载
}

@property(nonatomic, strong)UITableView *myTableView;

@property(nonatomic, strong)TableRefreshHeaderView *refreshHeaderView;

@property(nonatomic, strong)TableRefreshFooterView *loadingFooterView;

@end

ViewController.m

#import "ViewController.h"
#define UISCREEN_WIDTH [UIScreen mainScreen ].bounds.size.width
#define UISCREEN_HEIGHT [UIScreen mainScreen ].bounds.size.height
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    rowCount = 20;
    isLoading = NO;
    isRefreshing = NO;
    drageMode = -1;
    [self.view addSubview:self.myTableView];
    [self.myTableView addSubview:self.refreshHeaderView];
    [self.myTableView addSubview:self.loadingFooterView];
    [self.myTableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)dealloc
{
    [self.myTableView removeObserver:self forKeyPath:@"contentOffset"];
}

- (UITableView *)myTableView
{
    if (!_myTableView) {
        _myTableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 50, UISCREEN_WIDTH, UISCREEN_HEIGHT - 50)];
        _myTableView.delegate = self;
        _myTableView.dataSource = self;
    }
    return _myTableView;
}

- (TableRefreshHeaderView *)refreshHeaderView
{
    if (!_refreshHeaderView) {
        _refreshHeaderView = [[TableRefreshHeaderView alloc]initWithFrame:CGRectMake(0, -30, UISCREEN_WIDTH, 30)];
    }
    return _refreshHeaderView;
}

- (TableRefreshFooterView *)loadingFooterView
{
    if (!_loadingFooterView) {
        _loadingFooterView = [[TableRefreshFooterView alloc]initWithFrame:CGRectMake(0, self.myTableView.contentSize.height, UISCREEN_WIDTH, 30)];
    }
    return _loadingFooterView;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return rowCount;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
    }
    cell.textLabel.text=[NSString stringWithFormat:@"%ld",indexPath.row+1];
    return cell;
}

-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    //如果列表控件加载完毕且当前为下拉加载,则将下拉加载视图移到列表可视范围之外
    if([indexPath row] == ((NSIndexPath*)[[tableView indexPathsForVisibleRows] lastObject]).row && drageMode == 2){
        self.myTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
    }
}

//监听UITableview的顶部和头部下拉事件
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"contentOffset"] && !isLoading && !isRefreshing) {
        self.loadingFooterView.frame = CGRectMake(0, self.myTableView.contentSize.height, UISCREEN_WIDTH, 30);
        if (self.myTableView.isDragging) {
            if (self.myTableView.contentOffset.y > -45) {
                [self.refreshHeaderView setRefreshMode:1];
            }
            else if (self.myTableView.contentOffset.y < -45)
            {
                [self.refreshHeaderView setRefreshMode:2];
            }
        }
        else
        {
            if (self.myTableView.contentOffset.y < -45)
            {
                drageMode = 1;
                self.myTableView.contentInset = UIEdgeInsetsMake(45, 0, 0, 0);
                [self.refreshHeaderView setRefreshMode:3];
                [self beginRefresh];
            }
            else if (self.myTableView.contentOffset.y  > self.myTableView.contentSize.height - self.myTableView.frame.size.height + 45)
            {
                drageMode = 2;
                    if (rowCount < 50) {
                    [self.loadingFooterView setLoadingMode:1];
                    [self beginLoading];
                }
                else
                {
                    [self.loadingFooterView setLoadingMode:2];
                    self.myTableView.contentInset = UIEdgeInsetsMake(0, 0, 45, 0);
                }
            }
        }
    }
}

//开始刷新
- (void)beginRefresh
{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        isRefreshing = YES;
        sleep(2);//处理耗时操作
        dispatch_async(dispatch_get_main_queue(), ^{
            [self endRefresh];//处理完之后更新界面
        });
    }) ;
}

//停止刷新
- (void)endRefresh
{
    [UIView animateWithDuration:0.3 animations:^{
        self.myTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
    }];
    [self.refreshHeaderView setRefreshMode:1];
    isRefreshing = NO;
}

//开始加载
- (void)beginLoading
{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
            isLoading = YES;
            rowCount += 10;
            self.myTableView.contentInset = UIEdgeInsetsMake(0, 0, 45, 0);
            sleep(2);//处理耗时操作
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.myTableView reloadData];
            [self endLoading];//处理完之后更新界面
        });
    }) ;
}

//停止加载
- (void)endLoading
{
    if (rowCount >= 50) {
        [self.loadingFooterView setLoadingMode:2];
        self.myTableView.contentInset = UIEdgeInsetsMake(0, 0, 45, 0);
    }
    else
    {
        self.myTableView.contentInset = UIEdgeInsetsMake(0, 0, 45, 0);
        [self.loadingFooterView setLoadingMode:1];
    }
    isLoading = NO;
}

@end

源码下载地址:http://download.csdn.net/detail/lzm2625347497/9601843

原文地址:https://www.cnblogs.com/lzmfywz/p/5765137.html