Working Pull to refresh with disabled bounce - ios

I have UItableview and active UIRefreshControl for pull to refresh action. So I am trying to disable bounce (that appears when I scroll UITableView) by unselecting "bounce" property of tableview in storyboard. But when I do this pull to refresh also stops working. What can I do about this? Should I manually disable only bottom bounce and left top bounce for UIRefreshControl ?
My viewDidLoad method:
override func viewDidLoad() {
super.viewDidLoad()
self.refreshControl = UIRefreshControl()
self.refreshControl!.attributedTitle = NSAttributedString(string: "Обновление")
self.refreshControl!.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
self.edgesForExtendedLayout = UIRectEdge.None;
tableView.allowsMultipleSelectionDuringEditing = false;
tableView.tableFooterView = UIView()
// menu button
if self.revealViewController() != nil {
menuButton.target = self.revealViewController()
menuButton.action = "revealToggle:"
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
}

I faced the same issue. After implementing some code, I got a result that -unfortunately- the refresh control won't get called without letting the tableView bouncing.

Related

TapGestureRecogniser doesn't work at all in the newly created UIViewController but works in all the old UIViewControllers made before

Proof that gesture is being added but not detected
import UIKit
class PlaybackSpeedController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(tapDetected(_:)))
view.addGestureRecognizer(tap)
}
#objc func tapDetected(_ tap : UITapGestureRecognizer){
print("hello")
}
}
This hello never gets triggered. what am I missing? Funny how I used to play with gestures but don't understand why this happens
What I do is I add a transparent view that has the same frame as the superview.
let transparentView = UIView(frame: view.frame)
transparentView.backgroundColor = .clear
And just adding the gesture recognizer on that view
Please make sure view is having userInteraction enabled & is tappable directly on screen, for that make sure your new view controller frame is correct.
Setting the UIViewController's view.backgroundColor property to be some colour instead of default one solved the issue for me

Is it possible to add a drag to reload horizontally for a collection view?

Update:
I belive it may not be possible given the folowing line in apples documentation:
When the user drags the top of the scrollable content area downward
Found here.
Let me know if there is a way to do this.
I am trying to make it so that when the user swipe left (the way you swipe up in many apps with tableViews to reload) in a collection view it will show a loading icon and reload data (the reload data part I can handle myself).
How can I detect this so I can call a reloadData() method?
Note: I am using a UICollectionView which only has one column and x rows. At the first cell if the user swipes left it should show a loading icon and reload data.
I am looking for a way to detect the slide left intended to reload.
What I have tried:
let refreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
viewDidLoadMethods()
refreshControl.tintColor = .black
refreshControl.addTarget(self, action: #selector(refresh), for: .valueChanged)
collectionView.addSubview(refreshControl)
collectionView.alwaysBounceHorizontal = true
But this only works vertically.
I solved this problem with the following, but I should note that there is no default fucntionality like there is for vertical refresh:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offset = scrollView.contentOffset
let inset = scrollView.contentInset
let y: CGFloat = offset.x - inset.left
let reload_distance: CGFloat = -80
if y < reload_distance{
shouldReload = true
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if let _ = scrollView as? UICollectionView {
currentlyScrolling = false
if shouldReload {
baseVC.showReloading()
reloadCollectionView()
}
}
}

How to reposition a UIRefreshControl

I have programmatically added a UIRefreshControl as a subview to my UICollectionView.
lazy var refreshControl: UIRefreshControl = {
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(MyPhotospotsViewController.handleRefresh(_:)), for: UIControlEvents.valueChanged)
refreshControl.tintColor = UIColor.lightGray
return refreshControl
}()
override func viewDidLoad() {
super.viewDidLoad()
collectionView.addSubview(refreshControl)
}
I want to move it down slightly but nothing I have done so far has worked. I tried the following.
refreshControl.frame = CGRect(x: refreshControl.frame.origin.x,
y: refreshControl.frame.origin.y - 50,
width: refreshControl.frame.size.width,
height: refreshControl.frame.size.height)
I've also had a look on google but all the answers are in Objective C.
I was thinking of programmatically adding constraints, but that feels incorrect.
You should use autolayout constraints for it or update its frame in -viewDidLayoutSubviews.

How to add a floating button in UITableViewController which does not scroll when table is scrolled?

Currently there is a UITableViewContoller with many sections and rows.
What is the best way to add a button which floats on top of the table view. This button should not scroll when the cells are scrolled.
Currently I have the following code and with this the button still scrolls:
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(viewForFooter)
}
the viewForFooter is a separate view which contains the button which needs to be floating. Thank you. Any help would be greatly appreciated.
Here is an option if you really don't want to use a UIView with subviews...
override func viewDidLoad() {
super.viewDidLoad()
if let app = UIApplication.shared.delegate as? AppDelegate, let window = app.window {
print("adding view-with-button to keyWindow")
window.addSubview(viewForFooter)
viewForFooter.topAnchor.constraint(equalTo: window.topAnchor, constant: 120).isActive = true
viewForFooter.leftAnchor.constraint(equalTo: window.leftAnchor, constant: 40).isActive = true
}
// other stuff...
}
This will add the view as a subview of the "keyWindow" at 40,120, and will "hover" there while you scroll the table. I am assuming your viewForFooter is properly instantiated and you have the necessary constraints set up correctly.
The easiest way is to use a viewController that will contain the tableView as a subView and then You can add you floating button as a subview of the viewController
override func viewWillAppear(_ animated: Bool) {
self.btnPickup = UIButton()
self.btnPickup?.frame = CGRect(x: self.view.frame.size.width - 75, y: self.view.frame.size.height - 150, width: 50, height: 50)
// self.btnPickup?.setTitle("+", for: .normal)
self.btnPickup?.setBackgroundImage(#imageLiteral(resourceName: "add_user"), for: .normal)
self.btnPickup?.titleLabel?.textAlignment = .center
self.btnPickup?.titleLabel?.font = UIFont(name: (self.btnPickup?.titleLabel?.font.fontName)!, size: 50)
// self.btnPickup?.layer.borderColor = UIColor.black.cgColor
self.btnPickup?.backgroundColor = UIColor.white
// self.btnPickup?.layer.borderWidth = 1
self.btnPickup?.layer.cornerRadius = 25
self.btnPickup?.clipsToBounds = true
// self.btnPickup?.setTitleColor(UIColor.white, for: .normal)
self.btnPickup?.addTarget(self, action: #selector(DirectoryViewController.btnTapped(sender:)), for: .touchUpInside)
print(self.navigationController?.view.subviews.count ?? "error")
self.navigationController?.view.superview?.insertSubview(self.btnPickup!, at: (self.navigationController?.view.subviews.count)!)
}
override func viewWillDisappear(_ animated: Bool) {
self.btnPickup?.removeFromSuperview()
}
I had exactly this problem. I'm using Interface Builder
and Auto Layout to place it so, it is not a programtic solution like the ones suggest by my colleagues:
The button must be placed at the same level as the UITableView. Take care where you place it in the hierarchy as depicted below: It can not be below the Table View in the hierarchy.

What is the best way to hide UIRefreshControl iOS

I have trouble hiding refreshControl once a user leaves the ViewController while refreshControl is still visible. I have tried setting it removing it from superView (tableView), replacing it with new one, etc... The issue still remains with tableView when user returns to the screen, top content insets remain from refreshControl before and it leaves a white space on top of tableView and if I do not replace/hide refreshControl, it will be visible at this point.
Any suggestions?
Image: Transition between screens, refreshControl does not hide on viewDidDisappear
Try this one :-
refreshControl.tintColor = .clear
Initialize the refresh control:
lazy var refreshControl: UIRefreshControl = {
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action:
#selector(ViewController.handleRefresh(_:)),
for: UIControlEvents.valueChanged)
refreshControl.tintColor = UIColor.red
return refreshControl
}()
Handle the refresh and end the refreshing:
func handleRefresh(_ refreshControl: UIRefreshControl) {
self.tableView.reloadData()
refreshControl.endRefreshing()
}
Add the refresh control:
self.tableView.addSubview(self.refreshControl)
When you present the new screen just use .endRefreshing() on your refreshControl.
I have contacted a friend that gave a really nice answer. This was the code that helped me smoothly remove refreshControl in case it was stuck in frozen state on screen:
func forceHideRefreshControl(tableView: UITableView) {
if tableView.contentOffset.y < 0 { // Move tableView to top
tableView.setContentOffset(CGPoint.zero, animated: true)
}
}
Though if view controller hasn't finished loading, it won't have refreshControl visible. For that you'd need to call beginRefreshing() on it again, but I would do it with delay to avoid any animation problems. In any case, I think this was the best solution that actually removed the white spacing on top. I do not know why endRefreshing() did not work, but at least I found another way. Hope this helps anyone! :)
NOTE: However, this solution is tested on stuck/frozen refreshControl only. I do not know what effect it will have if you do not have this problem, but still use this solution for hiding refreshControl.

Resources