How can I get the scroll/swipe direction for up/down in a VC?
I want to add a UIScrollView or something else in my VC that can see if the user swipes/scrolls up or d
Simply add this method to your view controller:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.y < 0) {
// Move UP - Show Navigation Bar
self.navigationController?.setNavigationBarHidden(false, animated: true)
} else if (scrollView.contentOffset.y > 0) {
// Move DOWN - Hide Navigation Bar
self.navigationController?.setNavigationBarHidden(true, animated: true)
}
}
I have tried every single response in this thread but none of them could provide a proper solution for a tableView with bounce enabled. So I just used parts of solutions along with some all-time classic boolean flag solution.
1) So, first of all you could use an enum for the scrollDirection:
enum ScrollDirection {
case up, down
}
2) Set 3 new private vars to help us store lastOffset, scrollDirection and a flag to enable/disable the scroll direction calculation (helps us ignore the bounce effect of tableView) which you will use later:
private var shouldCalculateScrollDirection = false
private var lastContentOffset: CGFloat = 0
private var scrollDirection: ScrollDirection = .up
3) In the scrollViewDidScroll add the following:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// The current offset
let offset = scrollView.contentOffset.y
// Determine the scolling direction
if lastContentOffset > offset && shouldCalculateScrollDirection {
scrollDirection = .down
}
else if lastContentOffset < offset && shouldCalculateScrollDirection {
scrollDirection = .up
}
// This needs to be in the last line
lastContentOffset = offset
}
4) If you have not implemented scrollViewDidEndDragging implement it and add these lines of code inside it:
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
guard !decelerate else { return }
shouldCalculateScrollDirection = false
}
5) If you have not implemented scrollViewWillBeginDecelerating implement it and add this line of code inside it:
func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
shouldCalculateScrollDirection = false
}
6) Finally, If you have not implemented scrollViewWillBeginDragging implement it and add this line of code inside it:
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
shouldCalculateScrollDirection = true
}
And if you followed all the steps above you are good to go!
You could go to wherever you want to use the direction and simply write:
switch scrollDirection {
case .up:
// Do something for scollDirection up
case .down:
// Do something for scollDirection down
}
you could do something like this:
fileprivate var lastContentOffset: CGPoint = .zero
func checkScrollDirection(_ scrollView: UIScrollView) -> UIScrollViewDirection {
return lastContentOffset.y > scrollView.contentOffset.y ? .up : .down
}
and with scrollViewDelegate:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
switch checkScrollDirection(scrollView) {
case .up:
// move up
case .down:
// move down
default:
break
}
lastContentOffset = scrollView.contentOffset
}
For Swift I think the simplest and most powerful is to do like below.
It allows you to track when direction changed and react only once when it changed.
Plus you can always access the .lastDirection
scrolled property if you need to consult that in your code at any other stage.
enum WMScrollDirection {
case Up, Down, None
}
class WMScrollView: UIScrollView {
var lastDirection: WMScrollDirection = .None {
didSet {
if oldValue != lastDirection {
// direction has changed, call your func here
}
}
}
override var contentOffset: CGPoint {
willSet {
if contentOffset.y > newValue.y {
lastDirection = .Down
}
else {
lastDirection = .Up
}
}
}
}
The above assumes you are only tracking up/down scrolling.
It is customizable via the enum. You could add/change to .left
and .right
to track any direction.
I hope this helps someone.
Cheers
Another option, is use to use the UISwipeGestureRecognizer
that will recognize the swipe to requested direction (That will work on all views and not only on UIScrollView
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let upGs = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.handleSwipes(sender:)))
let downGs = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.handleSwipes(sender:)))
upGs.direction = .up
downGs.direction = .down
self.view.addGestureRecognizer(upGs)
self.view.addGestureRecognizer(downGs)
}
@objc func handleSwipes(sender:UISwipeGestureRecognizer) {
if (sender.direction == .up) {
print("Up")
}
if (sender.direction == .down) {
print("Down")
}
}
}
For swift4
Implement the scrollViewDidScroll
method that detects when you pan gesture beyond a y-axis of 0:
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
if(scrollView.panGestureRecognizer.translation(in: scrollView.superview).y > 0) {
print("up")
}
else {
print("down")
}
}