Cocoa学习

我的Cocoa/Cocoa Touch学习笔记

用代码触发下拉更新

UIRefreshControl是iOS 6中的一个新控件,这个控件就是大家熟悉的下拉更新控件。关于如何把UIRefreshControl集成至UITableViewController中相信大家都知道怎么做。至于用代码触发下拉更新,查看Apple的文档后,我们看到UIRefreshControl有一个方法:- beginRefreshing。写到这里,貌似问题依然解决,没什么好说的了。但是真是这样吗?让我们来创建一个测试项目进行验证:

  1. 创建一个Master-Detail Application项目,取名“RefreshControl”(你可以随便取),设备选iPhone,够上“Use Automatic Reference Counting”和“Use Storyboards”(你也可以不用Storyboard,反正差不多)。

  2. (可选)打开MainStoryboard.storyboard(或MasterViewController.xib,如果你在1中没有勾选Use Storyboards),启用Master View Controller的Refreshing。

  3. 打开MasterViewController.m,更改代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
- (void)viewDidLoad
{
    [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.
    self.navigationItem.leftBarButtonItem = self.editButtonItem;
    // self.refreshControl = [[UIRefreshControl alloc] init]; // 如果你没有做步骤2,取消注释本行。
    [self.refreshControl addTarget:self action:@selector(insertNewObject:) forControlEvents:UIControlEventValueChanged]; // 设置下拉刷新时执行的动作

    UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addButtonAction:)]; // 通过代码触发下拉刷新动作
    self.navigationItem.rightBarButtonItem = addButton;
}

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

// 下拉刷新动作
- (void)addButtonAction:(id)sender {
    [self.refreshControl beginRefreshing]; // 触发刷新动作
}

- (void)insertNewObject:(id)sender
{
    // 使用Timer来模拟一个耗时的操作
    [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(doSomething) userInfo:nil repeats:NO];
}

// 这是模板自动生成的插入新项目的代码,我们把它移入了一个新方法,并增加结束刷新的代码。
- (void)doSomething {
    if (!_objects) {
        _objects = [[NSMutableArray alloc] init];
    }
    [_objects insertObject:[NSDate date] atIndex:0];
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.refreshControl endRefreshing]; // 结束刷新
}

编译执行。

首先,我们先测试手动下拉刷新--如果你设置正确的话,程序运行良好,下拉更新OK了。

然后,我们试试点击右上角的“+”按钮。我们希望它也能正常运行。但是这时候,问题出现了--好像程序啥都没有做!但是实际上,UIRefreshControl确实在工作了。不信你可以把TableView往下拉一点,我们能看到进度圈在转。但是奇怪的是,- doSomething代码似乎没有执行。

为了解决这个问题,我们在- addButtonAction:方法中在调用- beginRefreshing之后加入一行代码:

1
2
3
[self insertNewObject:nil]; //手工执行插入新行的动作
// 或者
[self.refreshControl sendActionsForControlEvents:UIControlEventValueChanged]; //发送ValueChanged事件(推荐)

再次编译执行后,我们发现- doSomething可以正确执行了,但是,进度圈还是藏在TableView可见范围的上方。为了解决这个问题,我们需要在- addButtonAction:方法中,在调用- beginRefreshing之前再加入一行代码:

1
[self.tableView setContentOffset:CGPointMake(0, -44) animated:YES];

编译执行,点击“+”按钮,进度圈出现,2秒后,新条目加入,进度圈消失,我们的问题也解决了。

总结一下,用代码触发下拉更新有两个陷阱:1. 调用- beginRefreshing方法不会触发UIControlEventValueChanged事件;2. 调用- beginRefreshing方法不会自动显示进度圈。

示例代码已经上传至github。如果你有更好的方法,或者你觉得我的处理方法有错误,请留言指正。谢谢。

(全文完)

Comments