在viewDidLoad中使用UIRefreshControl

26

我正在使用以下代码创建UIRefreshControl:

- (void) viewDidLoad
{
    [super viewDidLoad];

    UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
    [refreshControl addTarget:self action:@selector(doLoad) forControlEvents:UIControlEventValueChanged];
    self.refreshControl = refreshControl;
}

- (void) doLoad
{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
            // Instead of sleeping, I do a webrequest here.
            [NSThread sleepForTimeInterval: 5];

            dispatch_async(dispatch_get_main_queue(), ^{
                [tableView reloadData];
                [self.refreshControl endRefreshing];
            });
    });
}

它工作得很好。如果我导航到我的视图,拖动表格,代码运行并显示数据。

然而,我想要做的是在视图出现时将其设置为“加载”状态(这样用户就知道正在发生什么)。我尝试添加以下内容:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [self.refreshControl beginRefreshing];
}

但似乎不起作用。当我导航到视图时,它看起来像是常规视图(刷新控件不可见),而且当我尝试拉动刷新控件时,它从未完成加载。

显然,我做错了。您对我该如何处理有什么建议吗?


它对我有效。我做的事情完全相同。只是refreshControl的操作有一个sender属性。当我进入屏幕时,刷新控件不可见,但如果我将表视图向下拉一点,我就可以看到旋转的刷新控件。 - dasdom
4个回答

68

试试这个:

- (void) viewWillAppear: (BOOL) animated
{
    [super viewWillAppear: animated];

    self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);
    [self.refreshControl beginRefreshing];    

    // kick off your async refresh!
    [self doLoad];
}

记得在某个时刻调用 endRefreshing!

编辑添加完整的工作示例:

这个示例视图控制器,在 iOS 6.1 中建立并运行为根视图控制器时,启动应用程序时 UIRefreshControl 已经可见并正在动画。

TSTableViewController.h

@interface TSTableViewController : UITableViewController
@end

TSTableViewController.m

#import "TSTableViewController.h"

@implementation TSTableViewController
{
    NSMutableArray*    _dataItems;
}

- (void) viewDidLoad
{
    [super viewDidLoad];

    self.refreshControl = [UIRefreshControl new];

    [self.refreshControl addTarget: self
                            action: @selector( onRefresh: )
                  forControlEvents: UIControlEventValueChanged];
}

- (void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear: animated];

    self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);

    [self.refreshControl beginRefreshing];
    [self onRefresh: nil];
}

- (void) onRefresh: (id) sender
{
    double delayInSeconds = 2.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

        _dataItems = [NSMutableArray new];

        for ( int i = 0 ; i < arc4random() % 100 ; i++ )
        {
            CFUUIDRef uuid = CFUUIDCreate( NULL );

            [_dataItems addObject: CFBridgingRelease(CFUUIDCreateString( NULL, uuid)) ];

            CFRelease( uuid );
        }

        [self.refreshControl endRefreshing];

        [self.tableView reloadData];
    });
}

#pragma mark - Table view data source

- (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView
{
    return 1;
}

- (NSInteger) tableView:(UITableView *) tableView numberOfRowsInSection: (NSInteger) section
{
    return _dataItems.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault
                                                   reuseIdentifier: nil];

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

    return cell;
}

@end

1
这对你起作用吗?我一直在尝试,但直到我在桌子上划动手指它才显示出来。 - Kyle
2
仅在调用beginRefreshing之前设置contentOffset才有效。 - ıɾuǝʞ
调整contentOffset确实可以使控件可见,但对我来说,即使在更改内容偏移量之前或之后调用beginRefreshing,它也不会旋转。 - Mark Krenek

15

手动修改 contentOffset 是不安全和错误的,有时会导致意外行为。以下解决方案完全不需要触及 contentOffset

func showRefreshControl(show: Bool) {
    if show {
        refreshControl?.beginRefreshing()
        tableView.scrollRectToVisible(CGRectMake(0, 0, 1, 1), animated: true)
    } else {
        refreshControl?.endRefreshing()
    }
}

1
这不是正确的。修改内容偏移量是完全有效的(并且通常是必要的),例如通过顶部布局指南的长度来偏移内容。 - Greg Brown
2
这不正确。它是完全有效的。毫无争议,那只是你的观点。你假设你是唯一一个接触contentOffset的人,但事实并非如此。问题在于,在刷新时必须重置内容偏移量 - 如果UIKit的其他组件可能同时修改偏移量,则不可能知道重置的正确值是什么。 - user187676
说“不安全和错误”是一种观点。而说修改内容偏移量是有效的则不是——事实上,苹果的滚动视图编程指南明确提到了设置内容偏移量。例如,为了考虑布局指南,您的应用程序可能需要手动设置偏移量。在viewDidLayoutSubviews中执行此操作可以确保您的代码对内容偏移量有最后的决定权。 - Greg Brown
1
我喜欢这种技巧,因为它似乎比修改偏移量更干净。然而,我发现由于我的表格为空,初始滚动会被忽略。使用tableView.scrollRectToVisible(CGRectMake(0, -1, 1, 1), animated: false)可以解决问题。并且,在第一次动画期间如果我再次拉动它,当到达119时,刷新控件高度会无缘无故地降低20个点,然后继续像没有发生过任何事情一样。 - joe

3
另一种选择是在视图出现时触发UIControlEventValueChanged,从而启动初始刷新。

0
   - (void) viewDidAppear: (BOOL) animated
   {
          [super viewDidAppear: animated];
          UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
          [refreshControl addTarget:self action:@selector(doLoad) forControlEvents:UIControlEventValueChanged];
          self.refreshControl = refreshControl;
          [self.refreshControl beginRefreshing];    

   }

你从未设置self.refreshControl


1
他在viewDidLoad中设置了self.refreshControl,这非常好。 - TomSwift
@TomSwift,viewWillAppear方法会首先被调用。 - Abdullah Shafique
5
不是太多,视图需要加载才能出现。请参阅:https://dev59.com/cW435IYBdhLWcg3w-lP2 - TomSwift

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接