Is it possibile add UIRefreshControl
at the bottom of the UITableView
?
I would use it to load more data.
Please, Any suggest?

- 2,290
- 8
- 35
- 56
8 Answers
I believe there won't be any simple solution to this problem. May be someone could write a separate library to implement this behaviour plus it will cause more complications once you cache data in tableview.
But let us break down the problem and that might help you in achieving what you want. I have used the following code to add more rows in the app:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
float endScrolling = scrollView.contentOffset.y + scrollView.frame.size.height;
if (endScrolling >= scrollView.contentSize.height)
{
NSLog(@"Scroll End Called");
[self fetchMoreEntries];
}
}
Or you could do something like that:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if ((scrollView.contentOffset.y + scrollView.frame.size.height) >= scrollView.contentSize.height)
{
if (!self.isMoreData)
{
self.MoreData = YES;
// call some method that handles more rows
}
}
}
You must have seen such methods in many question as i have described above and certainly not what you have asked for. But what you can do is while the above code in in process to load more data, you can add a subview and show a couple of images similar to what UIRefreshControl offers. Add the images in the subview to be shown as a progress until the above code gets executed. Home this helps.
By the way, i will suggest you not to do that as it will just waste your time for making something so smaller unless you are just doing it for learning purposes.

- 1,508
- 15
- 25
The following answer is in Xcode 8 and Swift 3.
first declare
var spinner = UIActivityIndicatorView()
than in viewDidLoad
method write the following code:
spinner = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
spinner.stopAnimating()
spinner.hidesWhenStopped = true
spinner.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 60)
tableView.tableFooterView = spinner
now finally override
the scrollViewDidEndDragging
delegate method with following:
override func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
let offset = scrollView.contentOffset
let bounds = scrollView.bounds
let size = scrollView.contentSize
let inset = scrollView.contentInset
let y = offset.y + bounds.size.height - inset.bottom
let h = size.height
let reloadDistance = CGFloat(30.0)
if y > h + reloadDistance {
print("fetch more data")
spinner.startAnimating()
}
}

- 1,787
- 2
- 23
- 30
-
1This si the most correct answer as of this year. I have been using CCBottomRefreshControl until I had to convetr my project to swift 3.0 and it started crashing everywhere. This is a much better solution. Thank you! – Paul Lehn Apr 26 '17 at 13:41
-
2Man, you saved my day. This is the best solution for swift 3 – Kautham Krishna Dec 06 '17 at 15:11
-
1True, this is best solution – Milan Kamilya Jan 10 '19 at 06:29
-
1Good answer! One small tweak: you initialize spinner = UIActivityIndicatorView() and then in viewDidLoad() you initialize it again with spinner = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge). You could eliminate one of those. – wildcat12 Apr 20 '20 at 15:11
-
Very good solution. Note that in latest Swift versions the "override" statement is not needed. – Arik Segal May 20 '21 at 15:08
You can use UIView to customize your refreshControl at bottom. Create UIView and add it to UITableView as footerView.
UIView* footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
[footerView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"refreshImage.png"]]];
tableView.tableFooterView = footerView;
Hide it: tableView.tableFooterView.hidden = YES;
Implement UIScrollView delegate -
(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if ((scrollView.contentOffset.y + scrollView.frame.size.height) >= scrollView.contentSize.height)
{
tableView.tableFooterView.hidden = NO;
// call method to add data to tableView
}
}
before adding data to tableView save current offset by CGPoint offset = tableView.contentOffset;
call reloadData then set previously saved offset back to tableView [tableView setContentOffset:offset animated:NO];
So that you can feel new data added at bottom.

- 1,005
- 18
- 33
-
1I'm using this on my iOS 7 app and it appears to work. I actually am setting my `tableFooterView` to a `UIRefreshControl` view – hunteros May 09 '14 at 23:46
-
1
I've been stuck on the same problem recently and write a category for UIScrollView class. Here it is CCBottomRefreshControl.

- 136
- 1
- 2
-
-
1Worked Perfectly for me. All the approaches that use UIScrollViewDelegate methods are a pain in the ass regarding performance. This method uses the Default UIRefreshControl element, which is awesomely better than every other approach I came across. – marcelosalloum Dec 18 '14 at 16:31
-
But I am getting an issue. I am not able to remove the UIRefreshcontroller after the loading of data. [refreshController endRefreshing] does nothing. – Shreesh Garg Feb 06 '15 at 10:44
-
-
Hey morbo, Can you please tell how we can reduce the height of size that is required for refresh function. Currently user need to scroll the table a lot to get refreshed the data. – Shreesh Garg Mar 19 '15 at 10:04
-
@ShreeshGarg I've added triggerVerticalOffset property to UIRefreshControl class, so now you're able to specify scroll offset to start refresh function. – morbo Feb 16 '17 at 07:15
Actually the free Sensible TableView framework does provide this functionality out of the box. You specify the batch number and it will automatically fetch the data, displaying the last cell as a 'load more' cell. Once you click that cell, it will automatically load the next batch, and so on. Worth taking a look at.

- 2,391
- 2
- 17
- 18
-
Please declare your affiliation with this framework (if any) at the moment this read like it might be spam. – ChrisF Jul 11 '13 at 12:51
-
1
-
For UITableView I suggest the following approach:
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
// if this is the last row that we have in local data
// and we didn't reach the total count of rows from the server side
if (count == indexPath.row+1 && count < total)
{
// .. fetch more rows and reload table when data comes
}
}
I didn't use the scroll view methods intentionally because the scroll view is slow. It happens that scroll view scrolls, we request more data, refresh more rows, and scroll view is not yet finished with scrolling, it is still decelerating and causing problems with fetching more data.

- 4,257
- 33
- 46
This Swift library add pull to refresh to the bottom of UITableview
.
https://github.com/marwendoukh/PullUpToRefresh-iOS
I hope this help you.

- 1,946
- 17
- 26
Use CCBottomRefreshControl in cocoapods,
As it is for language objective. you can add the pod file to your swift project then run it, i have done it, no problem occurs for me
Hope it helps.

- 379
- 4
- 13