I tried to use a UIRefreshControll in a UIScrollView but I had the problem that I needed to scroll a lot in order to get it to refresh. I needed to use both hands to make it work so I decided to write some scrolling logic to start the refreshing.
Now the problem is that sometimes the endRefreshing function doesn't make the UIRefreshControll view disappear and I end up having it there forever.
I have tried called endRefreshing in the main queue with a delay and it doesn't work. I have also tried setting isHidden to true and also removeFromSuperView. I've had no luck in making it work.
import UIKit
class RefreshableView : UIView {
@IBOutlet weak var scrollView: UIScrollView!
private let refreshControl = UIRefreshControl()
private var canRefresh = true
var refreshFunction: (() -> ())?
func setupUI() {
backgroundColor = ColorName.grayColor.color
scrollView.refreshControl = refreshControl
}
func endRefreshing() {
self.refreshControl.endRefreshing()
}
}
extension RefreshableView: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y < -100 {
if canRefresh && !self.refreshControl.isRefreshing {
self.canRefresh = false
self.refreshControl.beginRefreshing()
self.refreshFunction?()
}
} else if scrollView.contentOffset.y >= 0 {
self.canRefresh = true
}
}
}
The scroll view's refreshControl
handles the pull-to-refresh feature automatically, so you don't need any of the scrollViewDidScroll()
code.
Assuming your storyboard looks something like this, where:
RefreshableView
class@IBOutlet
)Your code can be like this:
class RefreshableView : UIView {
@IBOutlet var scrollView: UIScrollView!
private let refreshControl = UIRefreshControl()
var refreshFunction: (() -> ())?
func setupUI() {
backgroundColor = .gray
refreshControl.addTarget(self, action: #selector(didPullToRefresh), for: .valueChanged)
scrollView.refreshControl = refreshControl
}
@objc func didPullToRefresh() {
print("calling refreshFunction in controller")
self.refreshFunction?()
}
func endRefreshing() {
print("end refreshing called from controller")
self.refreshControl.endRefreshing()
}
}
class RefreshTestViewController: UIViewController {
@IBOutlet var theRefreshableView: RefreshableView!
override func viewDidLoad() {
super.viewDidLoad()
theRefreshableView.setupUI()
theRefreshableView.refreshFunction = {
print("simulating refresh for 2 seconds...")
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
[weak self] in
guard let self = self else { return }
// do what you want to update the contents of theRefreshableView
// ...
// then tell theRefreshableView to endRefreshing
self.theRefreshableView.endRefreshing()
}
}
}
}