How to get UIScrollView vertical direction in Swif

2020-01-28 02:36发布

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 down and then hide/show a UIView depending if it was an up/down gesture.

11条回答
Summer. ? 凉城
2楼-- · 2020-01-28 03:13

Swift 2-4 with UISwipeGestureRecognizer

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")
        }
    }
}
查看更多
等我变得足够好
3楼-- · 2020-01-28 03:15

I made protocol to reuse Scroll Directions.

Declare these enum and protocols.

enum ScrollDirection {
    case up, left, down, right, none
}

protocol ScrollDirectionDetectable {
    associatedtype ScrollViewType: UIScrollView
    var scrollView: ScrollViewType { get }
    var scrollDirection: ScrollDirection { get set }
    var lastContentOffset: CGPoint { get set }
}

extension ScrollDirectionDetectable {
    var scrollView: ScrollViewType {
        return self.scrollView
    }
}

Usage From ViewController

// Set ScrollDirectionDetectable which has UIScrollViewDelegate
class YourViewController: UIViewController, ScrollDirectionDetectable {
    // any types that inherit UIScrollView can be ScrollViewType
    typealias ScrollViewType = UIScrollView
    var lastContentOffset: CGPoint = .zero
    var scrollDirection: ScrollDirection = .none

}
    extension YourViewController {
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            // Update ScrollView direction
            if self.lastContentOffset.x > scrollView.contentOffset.x {
                scrollDirection = .left
            } else if self.lastContentOffset.x > scrollView.contentOffset.x {
                scrollDirection = .right
            }

            if self.lastContentOffset.y > scrollView.contentOffset.y {
                scrollDirection = .up
            } else if self.lastContentOffset.y < scrollView.contentOffset.y {
                scrollDirection = .down
            }
            self.lastContentOffset.x = scrollView.contentOffset.x
            self.lastContentOffset.y = scrollView.contentOffset.y
        }
    }

If you want to use specific direction, just update specific contentOffset that you want.

查看更多
冷血范
4楼-- · 2020-01-28 03:24

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

查看更多
戒情不戒烟
5楼-- · 2020-01-28 03:28

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
}
查看更多
我命由我不由天
6楼-- · 2020-01-28 03:29

I used Victor's answer with a minor improvement. When scrolling past the end or beginning of the scroll, and then getting the bounce back effect. I have added the constraint by calculating scrollView.contentSize.height - scrollView.frame.height and then limiting the scrollView.contentOffset.y range to be greater than 0 or less than scrollView.contentSize.height - scrollView.frame.height, no changes are made when bouncing back.

func scrollViewDidScroll(_ scrollView: UIScrollView) {

    if lastContentOffset > scrollView.contentOffset.y && lastContentOffset < scrollView.contentSize.height - scrollView.frame.height {
        // move up
    } else if lastContentOffset < scrollView.contentOffset.y && scrollView.contentOffset.y > 0 {
        // move down
    }

    // update the new position acquired
    lastContentOffset = scrollView.contentOffset.y
}
查看更多
登录 后发表回答