When i want to the update data source of the tableview, firstly i want to scroll to top (to header view) then show the UIRefreshControl view, after data source updated then i want to hide the UIRefreshControll.
To do that i tried following line:
self.kisilerTable.scrollRectToVisible(CGRect(x: 0, y: 0, width: 1, height: 1), animated: false)
self.kisilerTable.setContentOffset(CGPoint(x: 0, y: self.kisilerTable.contentOffset.y - (self.refreshControl.frame.size.height)), animated: true)
self.kisilerTable.refreshControl?.beginRefreshing()
Above code is scrolling to top then it shows the UIRefreshControl. And after my data updated i tried to hide it with following code:
self.kisilerTable.reloadData()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.kisilerTable.refreshControl?.endRefreshing()
}
But the problem is, above code is hiding the indicator animation but it leaves a space there. As you can see in the screenshot:
If i try to hide with following code:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.kisilerTable.reloadData()
self.kisilerTable.refreshControl?.endRefreshing()
}
It is hiding but, i am losing the hide animation. I don't want to lose hide animation.
How can i resolve this problem?
I think it happens, because in the beginning you use setContentOffset to leave a space, but that space is not removed.
I will suggest another implementation, which works very well:
First you declare the refreshControll before the method viewDidLoad():
let refreshControl = UIRefreshControl()
Now do you need create a method for stop the animation when needed:
func stopAnimatingRefreshControl() {
if let refreshControl =
tableView.subviews.first(where: { $0 is UIRefreshControl})as? UIRefreshControl,
refreshControl.isRefreshing {
refreshControl.endRefreshing()
}
}
Now you create an #objc function that be called when scrolls the table to update, normally in this moment you call methods that make your server request to update data.
When this data is updated, you call the function stopAnimatingRefreshControl():
#objc func refreshMyData() {
// call methods for get data from server
getDataFromServer()
}
func getDataFromServer() {
// request completed and data is updated, now i need stop the loading.
DispatchQueue.main.async {
self.tableView.reloadData()
}
stopAnimatingRefreshControl()
}
Finally, after creating the necessary methods, you need to link our #objc function to refreshControll and our tableView, do it in method viewDidLoad() :
refreshControl.addTarget(self, action: #selector(refreshMyData), for: .valueChanged)
tableView.addSubview(refreshControl)
Now you're done, I hope I helped.
Related
I have a UITableViewController and I want to add the feature pull to refresh.
This is easy to add in the code, the problem is that I want to add a extra space during the load time and when this time over return to top and I found the next problem:
If I touch the screen while the view is moving to top, the scroll stop and don't return to top.
I have a example code to reproduce the problem
#IBAction func refreshControlValueChanged(_ sender: UIRefreshControl) {
let elementsCount = numbersElements.count
let offset = self.tableView.contentOffset.y - (self.refreshControl?.frame.height)!
self.tableView.setContentOffset(CGPoint(x: 0, y: offset), animated: false)
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.numbersElements.append(String(elementsCount + 1))
self.tableView.reloadData()
sender.endRefreshing()
}
}
I see that I can disable user iteration but I think that is not good fix...
Is there a solution I can use to fix this problem?
Regards and Thanks!
A.
I'm using UITableView with UIRefreshControl in my UIViewController. When user pulls down the UITableView, UIRefreshControl it works fine. Problem occurs when the data is being fetched. After successful fetching i want UIRefreshControl to stop animate and reload data in the table view.
Video related
The thing is that when I do it as below animation flickers, jumps and god know what else.
private func setupActions() {
mainView.refreshControl.addTarget(self, action: #selector(fetchSurveys), for: .valueChanged)
}
#objc private func fetchSurveys() {
viewModel.fetchSurveys(success: { [weak self] in
self?.mainView.configureEmptyTableView(isHidden: false)
self?.mainView.refreshControl.endRefreshing()
self?.mainView.tableView.reloadData()
}, failure: { [weak self] error in
self?.mainView.configureEmptyTableView(with: "Unable to fetch surveys. Please try again.", isHidden: true)
self?.mainView.refreshControl.endRefreshing()
})
}
I've tried many combinations of order of reloadData() and endRefreshing() and still it doesn't work correctly.
I have a table in view "A" that is inside a tab bar controller. When I scroll down to reload the table refresh control start animating.When press tab bar controller going in view "B" and later go back to view "A", refresh control is visible but isn't animating.
Can someone help me? thank
func refresh(sender:AnyObject)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
Call API for data
dispatch_async(dispatch_get_main_queue(), { () -> Void in
UPDATE UI
refreshControl.endRefreshing()
})
});
}
override func viewDidAppear(animated: Bool)
{
if(requestTerminated == false)
{
//Continue animate refresh control somehow
}
}
Suppose you have this situation in your controller A , for example in viewDidLoad:
//global var
var refreshControl:UIRefreshControl!
self.refreshControl = UIRefreshControl()
self.refreshControl.attributedTitle = NSAttributedString(string: "pull to refresh")
self.refreshControl.addTarget(self, action: #selector(MyTableViewController.pullToRefresh(_:)), forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(refreshControl)
As can you see you have your refreshControl add as a subview to your A table controller. When you go to another controller probably you present another controller (B) and when you come back to A your refresh is freezed or stucked.
You could start UIRefreshControl animation on viewWillAppear and end it on viewDidDisappear. During transition save the state of refresh process to know when to show UIRefreshControl.
You can use a boolean like this:
// Refresh state
var isRefreshing = false
// Call on viewWillApper
func superviewWillApper(){
if isRefreshing && !refreshControl.refreshing{
startRefreshAnimation()
}
}
// Call on viewDidDisapper
func superviewDidDisappear(){
endRefreshAnimation(false, dataFetched: !isRefreshing)
}
func startRefreshAnimation(){
refreshControl.beginRefreshing()
contentOffset = CGPointMake(0, -refreshControl.bounds.size.height)
isRefreshing = true
}
//Saves state of refresh
func endRefreshAnimation(wasEmpty: Bool, dataFetched: Bool){
refreshControl.endRefreshing()
isRefreshing = !dataFetched
if !wasEmpty{
setContentOffset(CGPointZero, animated: true)
}else{
setContentOffset(CGPointZero, animated: false)
}
}
in my swift 2 app i have a table view controller
where i added a custom search bar (dark grey row)
in the viewDidLoad i call
configureCustomSearchController()
this is the function:
func configureCustomSearchController() {
customSearchController = CustomSearchController(
searchResultsController: self,
searchBarFrame: CGRectMake(0.0, 0.0, MyTable.frame.size.width, 50.0),
MyTable.tableHeaderView = customSearchController.customSearchBar
customSearchController.searchBar.sizeToFit()
customSearchController.customDelegate = self
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
// DO SOMETHING
}
func didStartSearching() {
// DO SOMETHING
}
func didTapOnSearchButton() {
// DO SOMETHING
}
func didTapOnCancelButton() {
// DO SOMETHING
}
func didChangeSearchText(searchText: String) {
// DO SOMETHING
}
My Question is, how can i hide the searcher, if my tableview will appear and show the sidebar if i pull down.
a pull down refresh function is available.
i found my solution:
viewDidLoad
MYTable.contentInset = UIEdgeInsets(top: -1, left: 0, bottom: 0, right: 0)
this hide the searchbar on start and if i scroll a little bit up, the search Bar will be visible
if you want to show searchbar when user scroll down then add this Code
self.MyTable.tableHeaderView = customSearchController
self.MyTable.contentOffset = CGPointMake(0, CGRectGetHeight(customSearchController.frame))
customSearchController.delegate = self
If you want to hide the header which contains your custom search bar you can try the following solutions:
When you have to hide header (At start):
tableview.contentOffset = CGPointMake(0,44)
When you have to show header (On the pull down action ):
tableview.contentOffset = CGPointMake(0,0)
Ref:https://stackoverflow.com/a/14433304/4557505
Another option is
table.tableHeaderView = nil
And later if you want to show it then just assign it again,
table.tableHeaderView = theHeaderView;
You can find more information about this on https://stackoverflow.com/a/8079933/4557505
Hope this may help you
Else you may set your search bar on the viewController's view and show/hide that based on your pull to refresh
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)
}
}