UIRefreshControl - beginRefreshing not working when UITableViewController is inside UINavigationController

wows picture wows · Feb 6, 2013 · Viewed 65k times · Source

I've setup a UIRefreshControl in my UITableViewController (which is inside a UINavigationController) and it works as expected (i.e. pull down fires the correct event). However, if I programmatically invoke the beginRefreshing instance method on the refresh control like:

[self.refreshControl beginRefreshing];

Nothing happens. It should animate down and show the spinner. The endRefreshing method works properly when I call that after the refresh.

I whipped up a basic prototype project with this behavior and it works properly when my UITableViewController is added directly to application delegate's root view controller, e.g:

self.viewController = tableViewController;
self.window.rootViewController = self.viewController;

But if I add the tableViewController to a UINavigationController first, then add the navigation controller as the rootViewController, the beginRefreshing method no longer works. E.g.

UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:tableViewController];
self.viewController = navController;
self.window.rootViewController = self.viewController;

My feeling is this has something to do with the nested view hierarchies within the navigation controller not playing nice with the refresher control - any suggestions?

Thanks

Answer

Dmitry Shevchenko picture Dmitry Shevchenko · Feb 6, 2013

It seems that if you start refreshing programmatically, you have to scroll the table view yourself, say, by changing contentoffset

[self.tableView setContentOffset:CGPointMake(0, -self.refreshControl.frame.size.height) animated:YES];

I would guess the reason for this is that it could be undesirable to scroll to the refresh control when user is in the middle/bottom of the table view?

Swift 2.2 version by @muhasturk

self.tableView.setContentOffset(CGPoint(x: 0, y: -refreshControl.frame.size.height), animated: true)

In a nutshell, to keep this portable add this extension

UIRefreshControl+ProgramaticallyBeginRefresh.swift

extension UIRefreshControl {
    func programaticallyBeginRefreshing(in tableView: UITableView) {
        beginRefreshing()
        let offsetPoint = CGPoint.init(x: 0, y: -frame.size.height)
        tableView.setContentOffset(offsetPoint, animated: true)        
    }
}