IOS Table 下拉,上拉刷新数据

ios开发中,大量的用到了表格table。用到table的时候,有个常用的功能就是数据更新。通常有两种刷新方式:

1. 将表头往下拉

2. 将表尾往上拉

随便google了一下,这种例子很多,但是好像大多数都是表头往下拉的情况。因为工作中需要两种拉动效果,所以就不得不自己高一下了。

从网上下载了一个例子,也不知道从哪里下的,忘了。然后自己动手改了一下,支持两种拉动方式。


刷新控件

网上down的两个文件:EGORefreshTableHeaderView.h和EGORefreshTableHeaderView.m

里面有个class叫做EGORefreshTableHeaderView,给其中一个初始化函数加了个参数,用来指明头还是尾,如:

- (id)initWithFrame:(CGRect)frame IsHeader: (BOOL)bHeader;
至于具体的改动,这里就不介绍了,回头我把代码传上来,大家可以自己看。


如何使用

先创建一个Table,参考http://blog.csdn.net/zj510/article/details/8444310

然后我们可以给这个table加上刷新功能。

增加2个成员变量,一个是头,一个是尾

    EGORefreshTableHeaderView *_refreshHeaderView;
    EGORefreshTableHeaderView *_refreshFooterView;

增加一个_reloading变量,这个是用来控制并发的,就是不允许同时有多个刷新。

看caller的代码:

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

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

@interface KViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, EGORefreshTableHeaderDelegate>
{
    NSMutableArray* aryItems;
    
    EGORefreshTableHeaderView *_refreshHeaderView;
    EGORefreshTableHeaderView *_refreshFooterView;
    
    
	BOOL _reloading;
    int prevItemCount;
}

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

@end
注意caller类需要实现一个protocol:EGORefreshTableHeaderDelegate。

这个protocol有几个函数需要实现,看它的定义:

@protocol EGORefreshTableHeaderDelegate
- (void)egoRefreshTableHeaderDidTriggerRefresh:(EGORefreshTableHeaderView*)view;
- (BOOL)egoRefreshTableHeaderDataSourceIsLoading:(EGORefreshTableHeaderView*)view;
@optional
- (NSDate*)egoRefreshTableHeaderDataSourceLastUpdated:(EGORefreshTableHeaderView*)view;
@end
函数 egoRefreshTableHeaderDidTriggerRefresh就是刷新响应函数,我们可以在这里更新数据

函数egoRefreshTableHeaderDataSourceIsLoading用来标记当前是否有刷新任务在运行,我们的这个例子不可以同时有多个刷新任务

函数egoRefreshTableHeaderDataSourceLastUpdated是可选的,但是通常我们都会使用,就是返回一个更新完成的时间
ok,现在我们来看看我们的测试代码:

#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; // should return if data source model is reloading
	
}

- (NSDate*)egoRefreshTableHeaderDataSourceLastUpdated:(EGORefreshTableHeaderView*)view{
	
	return [NSDate date]; // should return date data source was last changed
	
}
这些代码相当的简单,

egoRefreshTableHeaderDidTriggerRefresh里面判断一下是头还是尾,然后调用各自的更新数据线程,注意需要将_reloading设置尾YES,表示已经有刷新任务在运行了。

egoRefreshTableHeaderDataSourceIsLoading简单的返回_reloading

egoRefreshTableHeaderDataSourceLastUpdated返回当前时间。


接下来看看刷新线程

//模拟一些数据,用户将header往下拉
- (void) GetMoreHeaderData
{
    @autoreleasepool {
        //     [NSThread sleepForTimeInterval:5];
        
        for (int i = 3; i > 0; i--) {
            NSString* str = [NSString stringWithFormat:@"item header %d", i];
            [aryItems insertObject:str atIndex:0];
        }
        
        
        [self performSelectorOnMainThread:@selector(FinishedLoadMoreHeaderData) withObject:nil waitUntilDone:YES];
    }
}

//用户将footer往上拉的时候,放一些模拟数据
- (void) GetMoreFooterData
{
    @autoreleasepool {
        prevItemCount = [aryItems count];
        for (int i = 1; i < 10; i++) {
            NSString* str = [NSString stringWithFormat:@"item footer %d", i];
            [aryItems addObject:str];
        }
        
        [self performSelectorOnMainThread:@selector(FinishedLoadMoreFooterData) withObject:nil waitUntilDone:YES];
    }
}

我这里创建了2个刷新新城函数,一个模拟3个数据,一个模拟9个数据.注意UI界面的更新不可以在辅助线程里面完成,这个是IOS限制的,那么我们只能在主线程里面更新。然后在辅助线程里面通过performSelectorOnMainThread在主线程里面运行2个函数。增加2个更新ui的函数,如下:

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

//footer上拉处理线程结束会调用这个函数
- (void) FinishedLoadMoreFooterData
{
    [_MyTableView reloadData];//重新装载数据
    
    [self PutFooterAtEnd];//将footer放到table的最后
    
    //将滚动条定位到上拉前的那一条item
    if (prevItemCount >= 1) {
        NSIndexPath* row = [NSIndexPath indexPathForRow:prevItemCount - 1 inSection:0];
        [_MyTableView scrollToRowAtIndexPath:row atScrollPosition:UITableViewScrollPositionNone animated:NO];
        
    }
    
    [_refreshFooterView refreshLastUpdatedDate];
    
    _reloading = NO;
    [_refreshFooterView egoRefreshScrollViewDataSourceDidFinishedLoading:_MyTableView];
    
}

代码也是相当的简单,主要需要做这些事情:

1. reload一下table;

2. 调用刷新控件的两个函数:refreshLastUpdateDate和egoRefreshScrollViewDataSourceDidFinishedLoading。

3. 将_reloading设置为NO,意思是一次刷新结束。

需要注意的是表尾刷新结束后,需要调整一下刷新控件的位置,因为表格里面的内容变多了,刷新控件需要往下挪。

看看响应的函数:

//将footer放到table的最后面
- (void) PutFooterAtEnd
{
    CGRect footerFrame = _refreshFooterView.frame;
    CGRect r = CGRectMake(footerFrame.origin.x, _MyTableView.contentSize.height, _MyTableView.frame.size.width, footerFrame.size.height);
    
    if (r.origin.y < _MyTableView.frame.size.height) {
        r.origin.y = _MyTableView.frame.size.height;
    }
    _refreshFooterView.frame = r;
}

这样就是处理完了 EGORefreshTableHeaderDelegate相关的函数。

现在我们来ViewDidLoad里面初始化table,放一些模拟数据,然后给这个table加上上下刷新功能,如下:

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    _reloading = NO;
    
    aryItems = [[NSMutableArray alloc] initWithCapacity:0];
    [aryItems retain];
    
    for (int i = 0; i < 5; i++) {
        NSString* item = [NSString stringWithFormat:@"item %d", i];
        [aryItems addObject:item];
    }
    
    [self.MyTableView setDataSource:self];
    self.MyTableView.delegate = self;
    
    [self ShowHeaderAndFooter];
}

ShowHeaderAndFooter就是用来创建表头刷新和表尾刷新功能的,看:

- (void) ShowHeaderAndFooter
{
    if (_refreshHeaderView == nil) {
		_refreshHeaderView = [[EGORefreshTableHeaderView alloc] initWithFrame:CGRectMake(0.0f, 0.0f - _MyTableView.bounds.size.height, self.view.frame.size.width, _MyTableView.bounds.size.height) IsHeader: YES];
		_refreshHeaderView.delegate = self;
		[_MyTableView addSubview:_refreshHeaderView];
	}
    [_refreshHeaderView refreshLastUpdatedDate];
    
    if (_refreshFooterView == nil) {
		_refreshFooterView = [[EGORefreshTableHeaderView alloc] initWithFrame:
                              CGRectMake(0, -1000, self.view.frame.size.width, _MyTableView.bounds.size.height) IsHeader: NO];
		_refreshFooterView.delegate = self;
        [_MyTableView addSubview:_refreshFooterView];
        
        [self PutFooterAtEnd];//调整footer的位置
	}
    [_refreshFooterView refreshLastUpdatedDate];
    
}

好了,运行一下,我们可以看到表头表尾已经有刷新控件了,但是好像不起作用。

为什么刷新不工作呢?呵呵,我们漏了一个步骤:需要处理滚动条的滚动响应函数,加上以下代码:

#pragma mark -
#pragma mark UIScrollViewDelegate Methods

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

//告诉代理,滚动视图中的拖拉动作结束了
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    
    [_refreshHeaderView egoRefreshScrollViewDidEndDragging:scrollView];
    [_refreshFooterView egoRefreshScrollViewDidEndDragging:scrollView];
}
ok,现在就行了,再运行一下,发现可以刷新数据了,这个是将表头往下拉的情况

再试试将表尾往上拉:

嘿嘿,也成功了。到这里,我们就成功地加上了上下刷新效果。这里是个简单的例子,其实大多数代码都是差不多的,除了数据刷新部分。数据刷新看每个项目的情况的,只要在

GetMoreHeaderData和GetMoreFooterData里面更改就可以了。

 
总结

上下刷新的使用其实也是蛮简单的(怎么实现的刷新,这里不做探讨),这里画的图描述一下使用的基本步骤。


注意,数据生成部分一般都是起一个线程的,主线程用于ui显示,当数据生成结束的时候调用一把主线程来更新table


好了,简单介绍了一下上下刷新的使用,代码供参考:

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值