I'm trying to implement a pull to refresh feature in a UITableView within a UIViewController. I can't use a UITableViewController because I want the UITableView to be a smaller subview in the view controller, with some other stuff above it. I assume this is possible, but has anyone seen an implementation of it?
6 Answers
Add a refresh control directly to a UITableView
without using a UITableViewController
:
override func viewDidLoad() {
super.viewDidLoad()
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(refresh(_:)), for: .valueChanged)
if #available(iOS 10.0, *) {
tableView.refreshControl = refreshControl
} else {
tableView.backgroundView = refreshControl
}
}
@objc func refresh(_ refreshControl: UIRefreshControl) {
// Do your job, when done:
refreshControl.endRefreshing()
}

- 7,816
- 2
- 32
- 40
-
Thanks, I believe UIRefreshControl is new. I think this is now the best way to do this. – Daniel Robinson Feb 24 '13 at 19:19
-
So, basically the refreshControl becomes the header of UITableView? – user4951 Oct 22 '13 at 05:43
-
1Excellent and easy. It works for me when I tried it on a table view added to UIViewController on iOS 7.0.4. – thandasoru Feb 18 '14 at 05:45
-
6has anyone had the problem where the control itself is not visible but otherwise seems to work fine? – remotevision Mar 20 '14 at 20:38
-
Does not work properly if you have a positive top contentInset. – xissburg Apr 23 '14 at 20:41
-
16Table view seems to jump down unexpectedly once it "clicks". Not sure why yet. – Bob Spryn Apr 25 '14 at 01:21
-
3I found that it needs to go in viewdidappear, not sure if that is an iOS 7 feature - I am yet to test it in iOS 8... – Jack Solomon Sep 14 '14 at 06:36
-
1@BobSpryn every figure out why it jumps down when it "clicks". Very annoying and making me consider just using a UITableViewController. – Adam Johns Feb 11 '15 at 21:01
-
4The refreshControl appears on top of the tableView. I fixed this by: `tableView.insertSubview(refreshControl, atIndex: 0)` instead of `tableView.addSubview(refreshControl)` – kbpontius Dec 16 '15 at 16:50
-
the refresh control is not centered – OMGPOP Jan 04 '16 at 02:57
-
If the initial swipe makes refreshControl jump over the tableView, use clear background color refreshControl.backgroundColor = [UIColor clearColor]; You still will see the tableViews background, since the refreshControl is not above it but init. – Jakub Truhlář Apr 04 '16 at 12:11
-
Be careful with this method if you have tableview headers. The headers will float below the refresh control, yet the tableview content will scroll above refresh control giving an odd effect. This does not occur when setting a UIRefreshControl on a UITableViewController – user3847320 May 05 '16 at 02:11
-
1New way of using selector in Swift : #selector(YourClass.refresh) – CedricSoubrie Jul 06 '16 at 14:57
Objective-C:
This is how you can implement pull to refresh for table view. Same as in the case of collection view. Just replace table view alloc with collection view.
UITableView *tableViewDemo = [[UITableView alloc]init];
tableViewDemo.frame = CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height);
tableViewDemo.dataSource = self;
tableViewDemo.delegate = self;
[self.view addSubView: tableViewDemo];
UIRefreshControl *refreshController = [[UIRefreshControl alloc] init];
[refreshController addTarget:self action:@selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[tableViewDemo addSubview:refreshController];
#pragma mark - Handle Refresh Method
-(void)handleRefresh : (id)sender
{
NSLog (@"Pull To Refresh Method Called");
[refreshController endRefreshing];
}

- 9,564
- 146
- 81
- 122

- 245
- 2
- 7
-
How does the obj-c version only have 9 upvotes when the swift version has >430? – Chase Roberts Oct 17 '17 at 18:07
-
1@ChaseRoberts, That one is answered on Feb 13, have a look at the edit history, originally it was in objective-c, Since at that time swift was new, every one was looking for swift version... https://stackoverflow.com/posts/15010646/revisions – Irfan Oct 30 '17 at 06:43
This solution from @berik works fine but the UIController is displayed on top of the UITableViewController. The way to fix it is doing this change:
override func viewDidLoad() {
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: "refresh:", forControlEvents: .ValueChanged)
tableView.backgroundView = refreshControl // <- THIS!!!
}
func refresh(refreshControl: UIRefreshControl) {
// Do your job, when done:
refreshControl.endRefreshing()
}

- 11,439
- 12
- 48
- 87
-
3The refreshControl appears on top of the tableView for me, but your suggestion makes my `refreshControl` disappear, not appear below the `tableView`. I fixed this by: tableView.insertSubview(refreshControl, atIndex: 0) instead of tableView.addSubview(refreshControl) – kbpontius Dec 16 '15 at 16:57
I've implemented EGORefreshTableHeaderView with a UIViewController and a simple table view, the trick is that a in the places where EGO takes a scroll view as a parameter, if you look the table view itself inherits from scroll view.
It only requires that and a few extra connections :)
Hope this helps.

- 4,644
- 3
- 25
- 43
It seems that if you create the UIRefreshControl inside the viewController's loadView method everything works fine. The UIRefreshControl behaves as it should. Tested with iOS 7.1 and iOS 8.2
I ended up using ODRefreshControl.
It doesn't need any hack like the above tableView.backgroundView = refreshControl
, works almost the same way, and gives a better looking UI.

- 2,237
- 27
- 30
- 38

- 398
- 3
- 11