I am using this tutorial to implement a pull-to-refresh behavior with the RefreshControl
. I am using a Navigation Bar
. When using normal titles everything works good. But, when using "Prefer big titles" it doesn't work correctly as you can see in the following videos. Anyone knows why? The only change between videos is the storyboard check on "Prefer Large Titles".

- 20,070
- 9
- 74
- 84

- 5,308
- 6
- 33
- 65
-
1Does this help? https://stackoverflow.com/a/48347770/341994 – matt Jun 05 '18 at 20:27
12 Answers
I'm having the same problem, and none of the other answers worked for me.
I realised that changing the table view top constraint from the safe area to the superview fixed that strange spinning bug.
Also, make sure the constant value for this constraint is 0 .

- 1,680
- 1
- 17
- 15
-
3Was struggling since morning, this is the only solution that worked for me(iOS 12.1). Thanks! – vivek takrani Mar 23 '19 at 12:39
-
4
-
3
-
4combine it with: tableView.contentInsetAdjustmentBehavior = .always – Trzy Gracje Mar 27 '20 at 14:49
-
-
1
At the end what worked for me was:
In order to fix the RefreshControl progress bar disappearing bug with large titles:
self.extendedLayoutIncludesOpaqueBars = true
In order to fix the list offset after
refreshcontrol.endRefreshing()
:let top = self.tableView.adjustedContentInset.top let y = self.refreshControl!.frame.maxY + top self.tableView.setContentOffset(CGPoint(x: 0, y: -y), animated:true)

- 5,308
- 6
- 33
- 65
-
If you have opaque tab bar and the self.extendedLayoutIncludesOpaqueBars = true makes everything go under the tab bar and you don't want this behavior then you can add 'self.edgesForExtendedLayout = UIRectEdge.top' – Oleg Sherman Jan 21 '19 at 07:49
-
-
Check if you have any missing call of tableView.reloadData() before fixing the list offset, e.g. if you update tableHeaderView, you should call reloadData() immediately after it. – bojanb89 Jan 08 '21 at 12:02
If you were using tableView.tableHeaderView = refreshControl
or tableView.addSubView(refreshControl)
you should try using tableView.refreshControl = refreshControl

- 201
- 3
- 5
It seems there are a lot of different causes that could make this happen, for me I had a TableView embedded within a ViewController. I set the top layout guide of the tableview to the superview with 0. After all of that still nothing until I wrapped my RefreshControl end editing in a delayed block:
DispatchQueue.main.async {
if self.refreshControl.isRefreshing {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
self.refreshControl.endRefreshing()
})
}
}

- 133
- 1
- 3
-
Sadly, I had to go with this solution which does feel a bit hacky. I did get away with reducing + 1.0 down to + 0.2 – Sherwin Zadeh Mar 26 '20 at 01:09
The only working solution for me is combining Bruno's suggestion with this line of code:
tableView.contentInsetAdjustmentBehavior = .always

- 2,969
- 4
- 20
- 24
-
1Thank you! Without this line of code, Bruno's suggestion causes an issue with `UIScrollView.scrollsToTop`. (Note: You can also set this in IB in the Size Inspector pane.) – Arseniy Banayev Nov 11 '20 at 05:32
I've faced the same problem. Call refreshControl endRefreshing before calling further API.
refreshControl.addTarget(controller, action: #selector(refreshData(_:)), for: .valueChanged)
@objc func refreshData(_ refreshControl: UIRefreshControl) {
refreshControl.endRefreshing()
self.model.loadAPICall {
self.tableView.reloadData()
}
}

- 77
- 5
-
I did use OperationQueue and dependency between operations and it works good – NMaks Jul 18 '22 at 06:24
The only solution that worked for me using XIBs was Bruno's one: https://stackoverflow.com/a/54629641/2178888
However I did not want to use a XIB. I struggled a lot trying to make this work by code using AutoLayout.
I finally found a solution that works:
override func loadView() {
super.loadView()
let tableView = UITableView()
//configure tableView
self.view = tableView
}

- 222
- 1
- 6
- 15
I had this issue too, and i fixed it by embedded my scrollView (or tableView \ collectionView) inside stackView, and it's important that this stackView's top constraint will not be attached to the safeArea view (all the other constraints can). the top constraint should be connect to it's superview or to other view.

- 1,348
- 1
- 15
- 31
I was facing the same issue for very long, the only working solution for me was adding refresh control to the background view of tableview.
tableView.backgroundView = refreshControl

- 807
- 1
- 8
- 16
Short Answer
I fixed this by delaying calling to API until my collection view ends decelerating
Long Answer
I notice that the issue happens when refresh control ends refreshing while the collection view is still moving up to its original position. Therefore, I delay making API call until my collection view stops moving a.k.a ends decelerating. Here's a step by step:
- Follow Bruno's suggestion
- If you set your navigation bar's translucent value to false (
navigationBar.isTranslucent = false
), then you will have to setextendedLayoutIncludesOpaqueBars = true
on your view controller. Otherwise, skip this. - Delay api call. Since I'm using
RxSwift
, here's how I do it.
collectionView.rx.didEndDecelerating
.map { [unowned self] _ in self.refreshControl.isRefreshing }
.filter { $0 == true }
.subscribe(onNext: { _ in
// make api call
})
.disposed(by: disposeBag)
- After API completes, call to
refreshControl.endRefreshing()
Caveat
Do note that since we delay API call, it means that this whole pull-to-refresh process is not as quick as it could have been done without the delay.

- 555
- 3
- 9
- 16
Unfortunately, no advice helped. But I found a solution that helped me. Setting the transparency of the navigation bar helped.enter image description here

- 11
- 2
Problem can be solved if add tableview or scroll view as root view in UIViewController hierarchy (like in UITableViewController)
override func loadView() {
view = customView
}
where customView is UITableView or UICollectionView