您的位置:首页 > 其它

列表下拉/上拉刷新:(二)支持下拉/上拉的ViewController基类

2013-11-25 16:33 302 查看
目标:定义包含tableView的rootViewController类,其它需要此功能的ViewController可以直接继承,通过重载开始刷新数据的函数,执行自己实际的刷新和加载操作,其他关于footer/header复位、滚动等操作交给基类处理。

头文件:

[cpp] view
plaincopy

#import "EGORefreshTableHeaderView.h"

#import "EGORefreshTableFooterView.h"

#import "EGOViewCommon.h"

@interface RootViewController : UIViewController <EGORefreshTableDelegate, UITableViewDelegate, UITableViewDataSource>{

EGORefreshTableHeaderView *_refreshHeaderView;

EGORefreshTableFooterView *_refreshFooterView;

UITableView *_tableView;

// Reloading var should really be your tableviews datasource

// Putting it here for demo purposes

BOOL _reloading;

}

@property(nonatomic, retain)UITableView *tableView;

// create/remove footer/header view, reset the position of the footer/header views

-(void)setFooterView;

-(void)removeFooterView;

-(void)createHeaderView;

-(void)removeHeaderView;

// overide methods

-(void)beginToReloadData:(EGORefreshPos)aRefreshPos;

-(void)finishReloadingData;

@end

实现:

[cpp] view
plaincopy

#import "RootViewController.h"

@interface RootViewController (Private)

-(void)initTableViewWithRect:(CGRect)aRect;

@end

@implementation RootViewController

@synthesize tableView = _tableView;

- (void)viewDidLoad {

[super viewDidLoad];

// create the tableview

[self initTableViewWithRect:CGRectMake(self.view.bounds.origin.x,

self.view.bounds.origin.y,

self.view.frame.size.width,

self.view.frame.size.height-44.0)];

}

-(void)initTableViewWithRect:(CGRect)aRect{

_tableView = [[UITableView alloc] initWithFrame:aRect style:UITableViewStylePlain];

_tableView.delegate = self;

_tableView.dataSource = self;

_tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;

_tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth;

_tableView.backgroundColor = [UIColor clearColor];

[self.view addSubview: _tableView];

[_tableView release];

}

#pragma mark

#pragma methods for creating and removing the header view

-(void)createHeaderView{

if (_refreshHeaderView && [_refreshHeaderView superview]) {

[_refreshHeaderView removeFromSuperview];

}

_refreshHeaderView = [[EGORefreshTableHeaderView alloc] initWithFrame:

CGRectMake(0.0f, 0.0f - self.view.bounds.size.height,

self.view.frame.size.width, self.view.bounds.size.height)];

_refreshHeaderView.delegate = self;

[_tableView addSubview:_refreshHeaderView];

[_refreshHeaderView refreshLastUpdatedDate];

}

-(void)removeHeaderView{

if (_refreshHeaderView && [_refreshHeaderView superview]) {

[_refreshHeaderView removeFromSuperview];

}

_refreshHeaderView = nil;

}

-(void)setFooterView{

// if the footerView is nil, then create it, reset the position of the footer

CGFloat height = MAX(_tableView.contentSize.height, _tableView.frame.size.height);

if (_refreshFooterView && [_refreshFooterView superview]) {

// reset position

_refreshFooterView.frame = CGRectMake(0.0f,

height,

_tableView.frame.size.width,

self.view.bounds.size.height);

}else {

// create the footerView

_refreshFooterView = [[EGORefreshTableFooterView alloc] initWithFrame:

CGRectMake(0.0f, height,

_tableView.frame.size.width, self.view.bounds.size.height)];

_refreshFooterView.delegate = self;

[_tableView addSubview:_refreshFooterView];

}

if (_refreshFooterView) {

[_refreshFooterView refreshLastUpdatedDate];

}

}

-(void)removeFooterView{

if (_refreshFooterView && [_refreshFooterView superview]) {

[_refreshFooterView removeFromSuperview];

}

_refreshFooterView = nil;

}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

return YES;

}

#pragma mark-

#pragma mark force to show the refresh headerView

-(void)showRefreshHeader:(BOOL)animated{

if (animated)

{

[UIView beginAnimations:nil context:NULL];

[UIView setAnimationDuration:0.2];

self.tableView.contentInset = UIEdgeInsetsMake(60.0f, 0.0f, 0.0f, 0.0f);

// scroll the table view to the top region

[self.tableView scrollRectToVisible:CGRectMake(0, 0.0f, 1, 1) animated:NO];

[UIView commitAnimations];

}

else

{

self.tableView.contentInset = UIEdgeInsetsMake(60.0f, 0.0f, 0.0f, 0.0f);

[self.tableView scrollRectToVisible:CGRectMake(0, 0.0f, 1, 1) animated:NO];

}

}

#pragma mark -

#pragma mark overide UITableViewDataSource methods

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

return 0;

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

return 0;

}

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

static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {

cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

}

// Configure the cell.

return cell;

}

#pragma mark -

#pragma mark data reloading methods that must be overide by the subclass

-(void)beginToReloadData:(EGORefreshPos)aRefreshPos{

// should be calling your tableviews data source model to reload

_reloading = YES;

// overide, the actual loading data operation is done in the subclass

}

#pragma mark -

#pragma mark method that should be called when the refreshing is finished

- (void)finishReloadingData{

// model should call this when its done loading

_reloading = NO;

if (_refreshHeaderView) {

[_refreshHeaderView egoRefreshScrollViewDataSourceDidFinishedLoading:_tableView];

}

if (_refreshFooterView) {

[_refreshFooterView egoRefreshScrollViewDataSourceDidFinishedLoading:_tableView];

[self setFooterView];

}

// overide, the actula reloading tableView operation and reseting position operation is done in the subclass

}

#pragma mark -

#pragma mark UIScrollViewDelegate Methods

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{

if (_refreshHeaderView) {

[_refreshHeaderView egoRefreshScrollViewDidScroll:scrollView];

}

if (_refreshFooterView) {

[_refreshFooterView egoRefreshScrollViewDidScroll:scrollView];

}

}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{

if (_refreshHeaderView) {

[_refreshHeaderView egoRefreshScrollViewDidEndDragging:scrollView];

}

if (_refreshFooterView) {

[_refreshFooterView egoRefreshScrollViewDidEndDragging:scrollView];

}

}

#pragma mark -

#pragma mark EGORefreshTableDelegate Methods

- (void)egoRefreshTableDidTriggerRefresh:(EGORefreshPos)aRefreshPos{

[self beginToReloadData:aRefreshPos];

}

- (BOOL)egoRefreshTableDataSourceIsLoading:(UIView*)view{

return _reloading; // should return if data source model is reloading

}

// if we don't realize this method, it won't display the refresh timestamp

- (NSDate*)egoRefreshTableDataSourceLastUpdated:(UIView*)view{

return [NSDate date]; // should return date data source was last changed

}

#pragma mark -

#pragma mark Memory Management

- (void)didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

}

- (void)viewDidUnload {

SAFE_RELEASE(_refreshHeaderView)

SAFE_RELEASE(_refreshFooterView)

}

- (void)dealloc {

[super dealloc];

}

具体使用:

可以在一加载完view就createHeaderView,因为它总是在列表的最顶部,位置不会变化。不想要的时候remove。

footerView要在[tableView reloadData]之后才能设置,因为footer的位置取决于tableView的ContentSize。一般来讲:加载第一页数据之前,不需要创建footer,等到第一页的数据加载完成之后调用setFooterView(如果不存footer,会创建,否则重置位置),来首次创建footer,后续加载第二页、第三页...的时候,也是加载完成reloadData,之后setFooterView重新调整其位置。

重载-(void)beginToReloadData:(EGORefreshPos)aRefreshPos,具体实现你想做的事情,例如:

[cpp] view
plaincopy

#pragma mark-

#pragma mark overide methods

-(void)beginToReloadData:(EGORefreshPos)aRefreshPos{

[super beginToReloadData:aRefreshPos];

if (aRefreshPos == EGORefreshHeader) {

// pull down to refresh data

[self performSelector:@selector(testRealRefreshDataSource) withObject:nil afterDelay:2.0];

}else if(aRefreshPos == EGORefreshFooter){

// pull up to load more data

[self performSelector:@selector(testRealLoadMoreData) withObject:nil afterDelay:2.0];

}

}

如上,可以在这里触发联网操作获取数据,我用了延时操作来模拟而已。

给出我的完整的测试界面代码

示例:

[cpp] view
plaincopy

#import "MyTestViewController.h"

@interface MyTestViewController ()

@end

@implementation MyTestViewController

- (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view.

// test data

_totalNumberOfRows = 100;

_refreshCount = 0;

_dataSource = [[NSMutableArray alloc] initWithCapacity:4];

// set header

[self createHeaderView];

// the footer should be set after the data of tableView has been loaded, the frame of footer is according to the contentSize of tableView

// here, actually begin too load your data, eg: from the netserver

[self performSelector:@selector(testFinishedLoadData) withObject:nil afterDelay:2.0f];

}

- (void)viewDidUnload

{

[super viewDidUnload];

// Release any retained subviews of the main view.

}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

{

return (interfaceOrientation == UIInterfaceOrientationPortrait);

}

#pragma mark -

#pragma mark overide UITableViewDataSource methods

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

return _dataSource?1:0;

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

return _dataSource?_dataSource.count:0;

}

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

static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {

cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

}

// Configure the cell.

if (_dataSource && indexPath.row < _dataSource.count) {

cell.textLabel.text = [_dataSource objectAtIndex:indexPath.row];

}

return cell;

}

#pragma mark-

#pragma mark overide methods

-(void)beginToReloadData:(EGORefreshPos)aRefreshPos{

[super beginToReloadData:aRefreshPos];

if (aRefreshPos == EGORefreshHeader) {

// pull down to refresh data

[self performSelector:@selector(testRealRefreshDataSource) withObject:nil afterDelay:2.0];

}else if(aRefreshPos == EGORefreshFooter){

// pull up to load more data

[self performSelector:@selector(testRealLoadMoreData) withObject:nil afterDelay:2.0];

}

}

-(void)testRealRefreshDataSource{

NSInteger count = _dataSource?_dataSource.count:0;

[_dataSource removeAllObjects];

_refreshCount ++;

for (int i = 0; i < count; i++) {

NSString *newString = [NSString stringWithFormat:@"%d_new label number %d", _refreshCount,i];

[_dataSource addObject:newString];

}

// after refreshing data, call finishReloadingData to reset the header/footer view

[_tableView reloadData];

[self finishReloadingData];

}

-(void)testRealLoadMoreData{

NSInteger count = _dataSource?_dataSource.count:0;

NSString *stringFormat;

if (_refreshCount == 0) {

stringFormat = @"label number %d";

}else {

stringFormat = [NSString stringWithFormat:@"%d_new label number ", _refreshCount];

stringFormat = [stringFormat stringByAppendingString:@"%d"];

}

for (int i = 0; i < 20; i++) {

NSString *newString = [NSString stringWithFormat:stringFormat, i+count];

if (_dataSource == nil) {

_dataSource = [[NSMutableArray alloc] initWithCapacity:4];

}

[_dataSource addObject:newString];

}

_loadMoreCount ++;

// after refreshing data, call finishReloadingData to reset the header/footer view

[_tableView reloadData];

[self finishReloadingData];

}

-(void)testFinishedLoadData{

for (int i = 0; i < 20; i++) {

NSString *tableString = [NSString stringWithFormat:@"label number %d", i];

[_dataSource addObject:tableString];

}

// after loading data, should reloadData and set the footer to the proper position

[self.tableView reloadData];

[self setFooterView];

}

注:因为还要做一些进一步的加工,例如强制刷新等,所以代码还没写完,例如一进来的延迟2秒加载数据,感觉很奇怪,其实是为了后续要写的东西预留的,凑合看吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐