I am working on an application where I implement UIRefreshControl. All things going fine but when testing move on iPhone X or iPhone XR, pthen a weird problem raised.
The problem is UIRefreshControl Stucks sometimes when we try to refersh the list. Or we can say it occurring 1 out of 10 cases, If we uses it continuously. This issue is only generating in iPhone X or XR. In other device everything works fine.
If we talk about the code, I used the code which works perfectly. Here is a code snippet for UIRefreshControl.
Initialization:
lazy var refreshControl: UIRefreshControl? = {
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action:#selector(refreshAssignmentData(_:)), for: .valueChanged)
refreshControl.tintColor = CustomColors.themeColorGreen
return refreshControl
}()
I call this func in API, so when I get response it will add.
func addRefreshControl() {
/// Here adding refresh control
if #available(iOS 10.0, *) {
self.tblView?.refreshControl = self.refreshControl
} else {
self.tblView?.addSubview(self.refreshControl!)
}
refreshControl?.alpha = 1
}
And when we use pull to refresh this method calls
#objc func refreshAssignmentData(_ sender: Any) {
DispatchQueue.global(qos: .background).async {
self.performSelector(inBackground: #selector(self.getNewAssignmentListInBackground(_:)), with: nil)
}
DispatchQueue.main.async {
self.arrAllAssignment?.removeAll()
self.arrAllAssignment = [AssignmentModel]()
self.intPage = 1
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.refreshControl?.endRefreshing()
}
}
All these lines of code working fine in other device range except iPhone X series.
Any suggestion please...
Related
I'm trying to add pull to refresh on my wkwebview app. I'm using UIViewRepresentable for my webview, so I don't have the onViewLoad function and view controllers. Here's my code:
var wbWebViewEl: WKWebView = WKWebView()
struct SwiftUiWebView: UIViewRepresentable {
....
class refreshWebViewClass {
#objc func refreshWebView1(sender: UIRefreshControl) {
print("test debug :D")
wbWebViewEl.reload()
DispatchQueue.main.async {
sender.endRefreshing()
}
}
func makeUIView(context: Context) -> WKWebView {
......
wbWebViewEl.scrollView.bounces = true
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(refreshWebViewClass.refreshWebView1), for: UIControl.Event.valueChanged)
wbWebViewEl.scrollView.addSubview(refreshControl)
wbWebViewEl.scrollView.refreshControl = refreshControl
.....
}
.....
}
At the moment, when you swipe down, it shows the refresh loading spinner, but it doesn't stop spinning. Also the test print I put in the refreshWebView1 function, doesn't show in the logcat. Does anyone know what I'm getting wrong here? If you need to see anymore code let me know :)
Looks like your refreshWebViewClass should be a Coordinator. Then, in your addTarget, the target would be context.coordinator, not self, which doesn't make sense here, since self doesn't actually implement this method.
I have the following code for a button in my application to test my implementation of NVActivityIndicatorView:
#IBAction func goButtonPressed(_ sender: Any) {
self.startAnimatingActivityIndicator()
sleep(2)
self.stopAnimatingActivityIndicator()
}
The view controllers in my application also have this extension:
extension UIViewController: NVActivityIndicatorViewable {
func startAnimatingActivityIndicator() {
let width = self.view.bounds.width / 3
let height = width
let size = CGSize(width: width, height: height)
startAnimating(size, message: "Loading...", type: NVActivityIndicatorType.circleStrokeSpin)
}
func stopAnimatingActivityIndicator() {
self.stopAnimating()
}
}
The loading animations work elsewhere in the same view controller (i.e., the viewDidLoad() function) but for some reason I'm unable to get the loading animation to work on this button. The button is connected correctly as the application does sleep for the appropriate amount of time, but the loading animations fail to run.
Thanks in advance for the help!
The Indicator won't spin because the main thread is asleep. Use a 2 second timer to turn off the spinning instead.
#FryAnEgg coming in with the solution! The sleep(2) was preventing the loading animations from running.
Here's my updated code:
#IBAction func goButtonPressed(_ sender: Any) {
self.startAnimatingActivityIndicator()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
self.stopAnimatingActivityIndicator()
}
}
I have an UIRefreshControl which works on every device except iPhone 8 (works neither on a physical device or an emulator).
On an iPhone 8 the refresh indicator stops at 3/4 to the end and never calls refresh
This is how it looks like when you pull it all the way down:
Creating the refresh control:
lazy var refreshControl: UIRefreshControl = {
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action:
#selector(TeamViewController.handleRefresh(_:)),
for: UIControlEvents.valueChanged)
refreshControl.tintColor = UIColor.red
return refreshControl
}()
Adding to the view:
if #available(iOS 10.0, *) {
myCollectionView.refreshControl = refreshControl
} else {
myCollectionView.addSubview(refreshControl)
}
I had the same problem and was caused by me setting the view controller to freeform in the storyboard as the simulated size. Changing it back to fixed resolved the issue.
Can also be fixed by using:
override func viewDidLayoutSubviews() {
refreshControl?.didMoveToSuperview()
super.viewDidLayoutSubviews()
}
UIRefreshControl needs to be pulled down too far
I have a UITableView, that on the delegate of the UIViewController that adds a new item, inserts the row. The row gets correctly inserted.
However, the UIRefreshControl on the UITableView will not go away when dragging the UITableView after that.
extension FeedViewController: AddPostDelegate {
func didAddPost(_ userPost: UserPost) {
self.postsWrapper?.posts.insert(PostWrapper(type: PostType.user(userPost)), at: 0)
self.tableView.beginUpdates()
self.tableView.insertRows(at: [
IndexPath(row: 1, section: 0)
], with: .automatic)
self.tableView.endUpdates()
self.refresher.endRefreshing()//Does nothing
}
}
In viewDidLoad:
refresher = UIRefreshControl()
tableView.addSubview(refresher)
refresher.addTarget(self, action: #selector(didDragScrollView), for: .valueChanged)
refresher.layer.zPosition = -1//otherwise in front of the header cell when refreshing (iOS 9.2)
If I do not go to another view first than come back before attempting to pull for refresh, it always hangs spinning forever.
EDIT:
It looks like the UIRefreshControl is no longer calling the target function AFTER I add a post.
Any ideas on why this may be occurring? How to fix that?
Make sure that beginRefreshing() was not called before the user pulled to refresh. If refreshControl.isRefreshing is true then the selector does not get called upon "pull to refresh".
A simple test:
let refreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
refreshControl.addTarget(self, action: #selector(ViewController.refreshData), for: .valueChanged)
tableView.refreshControl = refreshControl
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// sets refreshControl.isRefreshing to true
// before the user initiates it
refreshControl.beginRefreshing()
}
Then the user pulls to refresh. Because refreshControl.isRefreshing is true the selector will not get called. If you remove refreshControl.beginRefreshing()in viewDidAppear, the selector will get called:
#objc func refreshData() {
print("refresh initiated")
refreshControl.endRefreshing()
}
Try assigning your UIRefreshControl into the refreshControl property of UITableView like this:
if #available(iOS 10.0, *) {
tableView.refreshControl = refresher
} else {
tableView.addSubview(refresher)
}
Note that this requires iOS 10.0 or higher, but we're soon getting iOS 12.0 so I don't think you should support iOS lower than 10.0
I am trying to show a refresh control right when the view loads to show that I am getting getting data from Parse. The refresh control works as it should when the app is running, but I cannot get it to fire programmatically from anywhere in my app.
This is the code that does not appear to run:
override func viewDidAppear(animated: Bool) {
self.refresher.beginRefreshing()
}
Not only does this not run, but having the code in the app changes the attributes of the refresh control. When I have this code in the app, and show the refresher from user interaction, the refresh control does not have its attributed title as it usually does nor does it run the code that it should.
I needed to add a delay between setContentOffset and the self.refreshControl?.sendActions(for: .valueChanged) call. Without the delay, the refreshControl's attributedTitle would not render.
This works in iOS 10 (Swift 3):
self.tableView.setContentOffset(CGPoint(x:0, y:self.tableView.contentOffset.y - (self.refreshControl!.frame.size.height)), animated: true)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2, execute: {
self.refreshControl?.sendActions(for: .valueChanged)
})
Here's an extension working on 10.3:
extension UIRefreshControl {
func refreshManually() {
if let scrollView = superview as? UIScrollView {
scrollView.setContentOffset(CGPoint(x: 0, y: scrollView.contentOffset.y - frame.height), animated: false)
}
beginRefreshing()
sendActions(for: .valueChanged)
}
}