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