How can I reveal the UIRefreshControl when I update the table programmatically? Using [self.refreshControl beginRefreshing] make the spinner animate but does not reveal it.
Asked
Active
Viewed 1.2k times
4 Answers
20
You'll have to manually change the contentOffset
of your UITableView
yourself. Be sure to account for the contentInset.top
. It should be something as simple as:
CGPoint newOffset = CGPointMake(0, -[myTableView contentInset].top);
[myTableView setContentOffset:newOffset animated:YES];

Dave DeLong
- 242,470
- 58
- 448
- 498
-
3I've noticed this tends to cause problems with cell drawing if you don't reset the contentOffset as well after you call `endRefreshing`: `[myTableView setContentOffset:CGPointZero animated:YES];` – Alan Zeino Jan 16 '13 at 05:18
-
2To fix that in iOS 8 or iOS 9, just call `[self.refreshControl beginRefreshing]` from `viewWillAppear:` method, not from `viewDidLoad:`. – Alexander Perechnev Mar 01 '16 at 15:09
-
2Anybody else who has the problem that the color of the spinning wheel is wrong when triggering the refresh by with beginRefresh()? In my case with a dark background it is black, but it is white when triggering the refresh with a pull. Setting the tint color does not help. – sofacoder Jul 14 '16 at 14:48
-
1@AlexanderPerechnev it worked for me in ios 9 in viewDidLoad but now in iOS 10 it doesnt even work in viewWillAppear – Bushra Shahid Sep 21 '16 at 13:03
-
@sofacoder Yep, I'm having the same issue. Tint color is black when beginRefreshing is called from viewWillAppear:, and nothing I do will change that. Changing the tintColor works from then on, but not on the first display. – itnAAnti Nov 11 '16 at 16:04
18
This will do the trick
- (void)beginRefreshingTableView {
[self.refreshControl beginRefreshing];
// check if contentOffset is zero
if (fabsf(self.tableView.contentOffset.y) < FLT_EPSILON) {
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);
} completion:^(BOOL finished){
}];
}
}

leviathan
- 11,080
- 5
- 42
- 40

Peter Lapisu
- 19,915
- 16
- 123
- 179
-
1Apparently you need to call `beginRefreshing` inside the completion block of the tableview animation, or after the animation call, otherwise the tintColor of the refreshControl set by you will be ignored. http://stackoverflow.com/a/20383030/903544 – René Nov 08 '15 at 14:43
9
For Swift 3, this is what I have based on Peter Lapisu's answer:
override func viewDidLoad() {
super.viewDidLoad()
self.refreshControl?.addTarget(self, action: #selector(refresh), forControlEvents: UIControlEvents.ValueChanged)
// ...
}
func refresh(sender:AnyObject) {
self.refreshControl?.beginRefreshing()
if let yOffsetTable = self.tableView?.contentOffset.y {
if yOffsetTable < CGFloat(Float.ulpOfOne) {
UIView.animate(withDuration: 0.25, delay: 0, options: UIViewAnimationOptions.beginFromCurrentState, animations: {
if let refreshControlHeight = self.refreshControl?.frame.height {
self.tableView?.contentOffset = CGPoint(x: 0, y: -refreshControlHeight)
}
}, completion: nil)
}
}
}

Gobe
- 2,559
- 1
- 25
- 24
7
For Swift 5, this is the only working version for me.
extension UIRefreshControl {
func beginRefreshingManually() {
if let scrollView = superview as? UIScrollView {
scrollView.setContentOffset(CGPoint(x: 0, y: scrollView.contentOffset.y - frame.height), animated: false)
}
beginRefreshing()
sendActions(for: .valueChanged)
}
}

LukasHromadnik
- 387
- 4
- 8
-
In the end, it turned out this is not what I needed, but your version works pretty well for sure! – choofie May 16 '22 at 16:46