IOS 带上下刷新功能的Table

上一个文章介绍了如何给table加上上下刷新功能,http://blog.csdn.net/zj510/article/details/8446833

假如我们在一个app里面有多处地方需要加上刷新功能,那么就会产生很多重复代码,因为有些代码是不变的。这样很不爽。有必要对他进行一些封装。

这里,就是尝试做一个简单的封装。


UITableView的子类:KRefreshTableView

通过xcode创建一个UITableView的子类,这个相当easy,我想ios开发者都会。

这个子类会实现刷新功能,为了有比较好的灵活性,我这里多加了一个回调,这个回调是用来数据更新的,因为大多数情况下,数据变化是挺大的,那么数据更新就由caller来指定吧。代码如下:

//
//  KRefreshTableView.h
//  DragList
//
//  Created by Kevin on 12-12-28.
//  Copyright (c) 2012年 Kevin. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "EGORefreshTableHeaderView.h"

@protocol DataUpdateCallback <NSObject>//定义一个回调,数据更新由调用者提供

@required
- (int) UpdateData: (BOOL) header;

@end

@interface KRefreshTableView : UITableView <EGORefreshTableHeaderDelegate>
{
    EGORefreshTableHeaderView *_refreshHeaderView;//表头刷新
    EGORefreshTableHeaderView *_refreshFooterView;//表尾刷新
    
    
	BOOL _reloading;
}

@property(retain, nonatomic) id<DataUpdateCallback> MyDelegate;//调用者,通过这个调用caller提供的数据更新回调
@property(retain, nonatomic) id Items;//指向调用者的数据,通常是一个NSMutableArray,可以得到一些数据信息

- (void) InitTable: (id) TableItems;//初始化
- (void) MyScrollViewDidScroll:(UIScrollView *)scrollView;
- (void) MyScrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;


@end
可以看到我里面加了一个DataUpdateCallback的协议,里面需要实现一个函数UpdateData。也就是说KRefreshTableView的调用者需要实现这个协议。


KRefreshTableView的具体实现代码就不介绍了。直接给出代码:

//
//  KRefreshTableView.m
//  DragList
//
//  Created by Kevin on 12-12-28.
//  Copyright (c) 2012年 Kevin. All rights reserved.
//

#import "KRefreshTableView.h"

@implementation KRefreshTableView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}



- (void)dealloc
{
    [self.MyDelegate release];
    [self.Items release];
    
    [super dealloc];
}

#pragma mark -- 处理下拉,上拉效果  --------------------------------
//将footer放到table的最后面
- (void) PutFooterAtEnd
{
    CGRect footerFrame = _refreshFooterView.frame;
    CGRect r = CGRectMake(footerFrame.origin.x, self.contentSize.height, self.frame.size.width, footerFrame.size.height);
    
    if (r.origin.y < self.frame.size.height) {
        r.origin.y = self.frame.size.height;
    }
    _refreshFooterView.frame = r;
}

- (void) ShowHeaderAndFooter
{
    if (_refreshHeaderView == nil) {
		_refreshHeaderView = [[[EGORefreshTableHeaderView alloc] initWithFrame:CGRectMake(0.0f, 0.0f - self.bounds.size.height, self.frame.size.width, self.bounds.size.height) IsHeader: YES] autorelease];
		_refreshHeaderView.delegate = self;//设置代理
		[self addSubview:_refreshHeaderView];//将刷新控件当作UITableView的子控件
	}
    [_refreshHeaderView refreshLastUpdatedDate];
    
    if (_refreshFooterView == nil) {
		_refreshFooterView = [[[EGORefreshTableHeaderView alloc] initWithFrame:
                              CGRectMake(0, -1000, self.frame.size.width, self.bounds.size.height) IsHeader: NO] autorelease];
		_refreshFooterView.delegate = self;
        [self addSubview:_refreshFooterView];//将刷新控件当作UITableView的子控件
        
        [self PutFooterAtEnd];//调整footer的位置
	}
    [_refreshFooterView refreshLastUpdatedDate];
    
}

//header下拉处理线程结束会调用这个函数
- (void) FinishedLoadMoreHeaderData: (NSNumber*) num
{
    //重新装载数据
    [self reloadData];
    
    [self PutFooterAtEnd];
    
    [_refreshHeaderView refreshLastUpdatedDate];//修改最后更新时间
    [_refreshHeaderView egoRefreshScrollViewDataSourceDidFinishedLoading:self];
    _reloading = NO;
}

//footer上拉处理线程结束会调用这个函数
- (void) FinishedLoadMoreFooterData: (NSNumber*) num
{
    [self reloadData];//重新装载数据
    
    [self PutFooterAtEnd];//将footer放到table的最后
    
    //将滚动条定位到上拉前的那一条item
    NSMutableArray* ary = self.Items;//table绑定的数据源
    int prevNum = [ary count]  - num.intValue;//得到更新前的行数
    if (prevNum >= 1) {
        NSIndexPath* row = [NSIndexPath indexPathForRow:prevNum - 1 inSection:0];
        //将table定位到更新时的位置
        [self scrollToRowAtIndexPath:row atScrollPosition:UITableViewScrollPositionNone animated:NO];
        
    }
    
    [num release];
    
    [_refreshFooterView refreshLastUpdatedDate];
    
    _reloading = NO;
    [_refreshFooterView egoRefreshScrollViewDataSourceDidFinishedLoading:self];
    
}


//模拟一些数据,用户将header往下拉
- (void) GetMoreHeaderData
{
    @autoreleasepool {
        [self.MyDelegate UpdateData:YES];//调用caller的数据更新回调,这样caller就可以设定需要更新的数据
        
        //更新数据完毕,在主线程里面更新ui
        [self performSelectorOnMainThread:@selector(FinishedLoadMoreHeaderData:) withObject:nil waitUntilDone:YES];
    }
}

//用户将footer往上拉的时候,放一些模拟数据
- (void) GetMoreFooterData
{
    @autoreleasepool {
        int ret = [self.MyDelegate UpdateData:NO];//获取增加的行数
        NSNumber* number = [NSNumber numberWithInt:ret];
        [number retain];//主线程需要release
        
        [self performSelectorOnMainThread:@selector(FinishedLoadMoreFooterData:) withObject:number waitUntilDone:YES];
    }
}

#pragma mark -
#pragma mark EGORefreshTableHeaderDelegate Methods

- (void)egoRefreshTableHeaderDidTriggerRefresh:(EGORefreshTableHeaderView*)view{
    //	NSLog(@"header: %@, footer: %@, view: %@", _refreshHeaderView, _refreshFooterView, view);
    
    if (view == _refreshFooterView) {
        NSLog(@"It's footer");
        
        _reloading = YES;//打开刷新标记,防止多个刷新任务同时刷新
        
        //启动一个线程来获取更新数据
        [NSThread detachNewThreadSelector:@selector(GetMoreFooterData) toTarget:self withObject:nil];
    }
    
    if (view == _refreshHeaderView) {
        NSLog(@"It's header");
        
        _reloading = YES;
        
        [NSThread detachNewThreadSelector:@selector(GetMoreHeaderData) toTarget:self withObject:nil];
    }
	
}

- (BOOL)egoRefreshTableHeaderDataSourceIsLoading:(EGORefreshTableHeaderView*)view{
	
	return _reloading; // 当前是否有刷新任务在运行,
	
}

- (NSDate*)egoRefreshTableHeaderDataSourceLastUpdated:(EGORefreshTableHeaderView*)view{
	
	return [NSDate date]; // 返回当前时间,这个时间会显示在更新时间
	
}

#pragma mark -
#pragma mark UIScrollViewDelegate Methods

//下面2个函数会被caller调用(caller的滚动响应函数里面调用)
//滚动响应,当用户在滚动视图中拉动的时候就会被触发(这里是指table中拉动)
- (void) MyScrollViewDidScroll:(UIScrollView *)scrollView{
    [_refreshHeaderView egoRefreshScrollViewDidScroll:scrollView];
    [_refreshFooterView egoRefreshScrollViewDidScroll:scrollView];
    
    //    NSLog(@"scrollViewDidScroll\n");
}

//告诉代理,滚动视图中的拖拉动作结束了
- (void) MyScrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    
    [_refreshHeaderView egoRefreshScrollViewDidEndDragging:scrollView];
    [_refreshFooterView egoRefreshScrollViewDidEndDragging:scrollView];
}


- (void) InitTable: (id) TableItems
{
    _reloading = NO;
    [self setItems:TableItems];
    
    [self ShowHeaderAndFooter];//创建表头表尾刷新控件
}

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

@end

ok,以上就是带刷新功能的Table的所有代码。


如何使用

怎么使用呢?很简单,跟使用标准table基本一样。

先拖一个UITableView到xib,然后指定class为KRefreshTableView,如图

然后在xib对应的controller的ViewDidLoad里面调用:

//初始化
    [_MyTableView InitTable: aryItems];

    //设置UITableView的代理
    _MyTableView.delegate = self;
    [_MyTableView setDataSource:self];
    //将当前对象传给KRefreshTableView,这样KRefreshTableView可以回调数据更新函数
    [_MyTableView setMyDelegate:self];

实现DataUpdateCallback协议函数UpdateData,如下:

//数据更新回调,KRefreshTableView的调用者需要实现协议:DataUpdateCallback,
//在协议函数UpdateData里面更新数据
- (int) UpdateData:(BOOL)header
{
    if (header) {
        for (int i = 4; i > 0; i--) {
            NSString* str = [NSString stringWithFormat:@"item header %d", i];
            [aryItems insertObject:str atIndex:0];
        }
        return 4;
    }
    else
    {
        for (int i = 1; i < 10; i++) {
            NSString* str = [NSString stringWithFormat:@"item footer %d", i];
            [aryItems addObject:str];
        }
        return 9;
    }
}
这里模拟了一些数据。

然后在滚动响应函数里面调用一下KRefreshTableView函数,如下:

#pragma mark -
#pragma mark UIScrollViewDelegate Methods

//滚动响应,当用户在滚动视图中拉动的时候就会被触发(这里是指table中拉动)
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    
    [_MyTableView MyScrollViewDidScroll:scrollView];
    //    NSLog(@"scrollViewDidScroll\n");
}

//告诉代理,滚动视图中的拖拉动作结束了
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    
    [_MyTableView MyScrollViewDidEndDragging:scrollView willDecelerate:decelerate];
    
}

其他的代码基本跟标准table一样,贴出所有代码:

KViewController.h

//
//  KViewController.h
//  DragList
//
//  Created by Kevin on 12-12-27.
//  Copyright (c) 2012年 Kevin. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "EGORefreshTableHeaderView.h"
#import "KRefreshTableView.h"

@interface KViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, DataUpdateCallback>
{
    NSMutableArray* aryItems;
    
    
}

@property (retain, nonatomic) IBOutlet KRefreshTableView *MyTableView;

@end

KViewController.m:

//
//  KViewController.m
//  DragList
//
//  Created by Kevin on 12-12-27.
//  Copyright (c) 2012年 Kevin. All rights reserved.
//

#import "KViewController.h"

#define ITEM_HEIGHT 50

@interface KViewController ()

@end

@implementation KViewController


- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    
    //模拟一些数据
    aryItems = [NSMutableArray arrayWithCapacity:0];
    [aryItems retain];
    
    for (int i = 0; i < 5; i++) {
        NSString* str = [NSString stringWithFormat:@"item %d", i];
        [aryItems addObject:str];
    }
    
    //初始化
    [_MyTableView InitTable: aryItems];

    //设置UITableView的代理
    _MyTableView.delegate = self;
    [_MyTableView setDataSource:self];
    //将当前对象传给KRefreshTableView,这样KRefreshTableView可以回调数据更新函数
    [_MyTableView setMyDelegate:self];
}

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

- (void)dealloc {
    [_MyTableView release];
    [aryItems release];
    [super dealloc];
}
- (void)viewDidUnload {
    [self setMyTableView:nil];
    [super viewDidUnload];
}

//数据更新回调,KRefreshTableView的调用者需要实现协议:DataUpdateCallback,
//在协议函数UpdateData里面更新数据
- (int) UpdateData:(BOOL)header
{
    if (header) {
        for (int i = 4; i > 0; i--) {
            NSString* str = [NSString stringWithFormat:@"item header %d", i];
            [aryItems insertObject:str atIndex:0];
        }
        return 4;
    }
    else
    {
        for (int i = 1; i < 10; i++) {
            NSString* str = [NSString stringWithFormat:@"item footer %d", i];
            [aryItems addObject:str];
        }
        return 9;
    }
}



#pragma mark -- table view delegate

- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 50;
}

#pragma mark -- DataSource


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [aryItems count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"MyTableViewCell";
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        NSArray *nib = [[NSBundle mainBundle]loadNibNamed:@"TableViewCell" owner:self options:nil];
        cell = [nib objectAtIndex:0];
    }
    
    if (cell) {
        UILabel* label = (UILabel*)[cell viewWithTag:1];
        
        NSString* item = [aryItems objectAtIndex: indexPath.row];
        [label setText:item];
    }
    
    
    return cell;
}

#pragma mark -
#pragma mark UIScrollViewDelegate Methods

//滚动响应,当用户在滚动视图中拉动的时候就会被触发(这里是指table中拉动)
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    
    [_MyTableView MyScrollViewDidScroll:scrollView];
    //    NSLog(@"scrollViewDidScroll\n");
}

//告诉代理,滚动视图中的拖拉动作结束了
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    
    [_MyTableView MyScrollViewDidEndDragging:scrollView willDecelerate:decelerate];
    
}

@end

运行一下,就可以看到带上下刷新的table了。这样只要需要刷新功能的地方,就可以用KRefreshTableView这个类代替标准的UITableView了。


整个工程例子,使用xcode4.5,

http://download.csdn.net/detail/zj510/4938673


©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页