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). Howe
None of the other answers worked for me. They would cause the spinner to show and spin, but the refresh action itself would never happen. This works:
id target = self;
SEL selector = @selector(example);
// Assuming at some point prior to triggering the refresh, you call the following line:
[self.refreshControl addTarget:target action:selector forControlEvents:UIControlEventValueChanged];
// This line makes the spinner start spinning
[self.refreshControl beginRefreshing];
// This line makes the spinner visible by pushing the table view/collection view down
[self.tableView setContentOffset:CGPointMake(0, -1.0f * self.refreshControl.frame.size.height) animated:YES];
// This line is what actually triggers the refresh action/selector
[self.refreshControl sendActionsForControlEvents:UIControlEventValueChanged];
Note, this example uses a table view, but it could just as well have been a collection view.
If you use Rxswift for swift 3.1, can use below:
func manualRefresh() {
if let refreshControl = self.tableView.refreshControl {
self.tableView.setContentOffset(CGPoint(x: 0, y: -refreshControl.height), animated: true)
self.tableView.refreshControl?.beginRefreshing()
self.tableView.refreshControl?.sendActions(for: .valueChanged)
}
}
This work for swift 3.1, iOS 10.
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)
}
}
Fort Swift 2.2+
self.tableView.setContentOffset(CGPoint(x: 0, y: -refreshControl.frame.size.height), animated: true)
The already mentioned approach:
[self.refreshControl beginRefreshing];
[self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControl.frame.size.height) animated:YES];
would make the spinner visible. But it wouldn't animate. The one thing I changed is the order of these two methods and everything worked:
[self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControl.frame.size.height) animated:YES];
[self.refreshControl beginRefreshing];
In addition to @Dymitry Shevchenko solution.
I found nice workaround to this issue. You can create extension to UIRefreshControl
that overwrites method:
// Adds code forgotten by Apple, that changes content offset of parent scroll view (table view).
- (void)beginRefreshing
{
[super beginRefreshing];
if ([self.superview isKindOfClass:[UIScrollView class]]) {
UIScrollView *view = (UIScrollView *)self.superview;
[view setContentOffset:CGPointMake(0, view.contentOffset.y - self.frame.size.height) animated:YES];
}
}
You can use new class by setting custom class in Identity Inspector for refresh control in Interface Builder.