UITableView 使用 UIRefreshControl 闪烁

UITableView Flickering with UIRefreshControl

我在 UIViewControllerviewDidLoad: 方法中定义了 UITableViewUIRefreshControl,如下所示:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.refreshControl = [[UIRefreshControl alloc] init];
    [self.refreshControl addTarget:self action:@selector(refreshMessages) forControlEvents:UIControlEventValueChanged];
    UITableViewController *tableViewController = [[UITableViewController alloc] init];
    tableViewController.tableView = self.messagesTableView;
    tableViewController.refreshControl = self.refreshControl;  
}

- (void)refreshMessages {
    //load data items
    if ([self.refreshControl isRefreshing]) {
        [self.refreshControl endRefreshing];
    }

    [self.messagesTableView reloadData];
}

我使用自动调整单元格来更新单元格数据。重新加载数据时,UITableView 闪烁。有没有办法避免这种情况?

编辑 我已经链接了示例演示的 video 文件。 UITableView 重新加载数据,闪烁。我使用自动布局来更新动态单元格高度。

这里有一个 sample 代码可以重现这个问题。应拉动 UITableView 进行刷新。 table 视图在主队列中重新加载。正在使用自动布局调整单元格的大小。


问题是您同时调用了 -reloadData 和 -endRefreshing。两者都想更新视图。你需要把它们分开一点。

以下选项之一将起作用,具体取决于您希望在何处查看单元格更新:

[self.tableView reloadData];
[self.refreshControl performSelector:@selector(endRefreshing) withObject:nil afterDelay:0.5];

[self.refreshControl endRefreshing];
[self.tableView performSelector:@selector(reloadData) withObject:nil afterDelay:0.5];

第一个选项可能需要更少的延迟。即使是 0.0 秒似乎也适用于您的示例代码。这足以在下次屏幕刷新时获得 -endRefreshing 动画。

-(void)refreshMessages{

self.messages = [NSMutableArray new];
[self loadData];

[self.tableView reloadData];
[self.refreshControl endRefreshing];
}

可能正在调用 reloadData 并且 endRefreshing 可能导致闪烁发生所以我所做的是稍微修改了您的代码并删除了清除闪烁的调度块

- (void)refreshMessages{

self.messages = [NSMutableArray new];
[self loadData];
[self.tableView reloadData];
[self.refreshControl performSelector:@selector(endRefreshing) withObject:nil afterDelay:0.5];


//    double delayInSeconds = 0.5;
//    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t) (delayInSeconds * NSEC_PER_SEC));
//    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//        [self.refreshControl endRefreshing];
//    });

}

你试过了吗?

[self.messagesTableView beginUpdates];
[self.messagesTableView reloadSections:[NSIndexSet indexSetWithIndex:0/*target section*/]  withRowAnimation:UITableViewRowAnimationNone];
[self.messagesTableView endUpdates];

而不是:

[self.messagesTableView reloadData];

我猜问题出在使用 estimatedHeight 和 UITableViewAutomaticDimension 以及 uitableview 的 reloadData。已报告 here

延迟会起作用,但它仍然不是实现它的正确方法,除非你想要一个骇人听闻的解决方法。

我今天遇到了同样的问题,我设法使用 CATransaction 解决了这个问题,这是 Swift 中的代码片段,在 UITableViewController 中执行:

        CATransaction.begin()
        CATransaction.setCompletionBlock { () -> Void in
            /*wait for endRefreshing animation to complete 
              before reloadData so table view does not flicker to top 
              then continue endRefreshing animation */

            self.tableView.reloadData()
        }

        self.refreshControl!.endRefreshing()
        CATransaction.commit()

Swift

您可能想使用

extendedLayoutIncludesOpaqueBars = true

在您的 ViewController 中以获得正确的 UIRefreshControl 动画。