How to get UIScrollView vertical direction in Swift?

前端 未结 12 960
悲&欢浪女
悲&欢浪女 2020-12-01 01:51

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

相关标签:
12条回答
  • 2020-12-01 02:36

    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.

    0 讨论(0)
  • 2020-12-01 02:37

    If you use an UIScrollView then you can take benefit from the scrollViewDidScroll: function. You need to save the last position (the contentOffset) it have and the update it like in the following way:

    // variable to save the last position visited, default to zero
    private var lastContentOffset: CGFloat = 0
    
    func scrollViewDidScroll(scrollView: UIScrollView!) {
        if (self.lastContentOffset > scrollView.contentOffset.y) {
            // move up
        }
        else if (self.lastContentOffset < scrollView.contentOffset.y) { 
           // move down
        }
    
        // update the new position acquired
        self.lastContentOffset = scrollView.contentOffset.y
    }
    

    There are other ways of do it of course this is one to them.

    I hope this help you.

    0 讨论(0)
  • 2020-12-01 02:42

    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
    }
    
    0 讨论(0)
  • 2020-12-01 02:43

    Victor's answer is great, but it's quite expensive, as you're always comparing and storing values. If your goal is to identify the scrolling direction instantly without expensive calculation, then try this using Swift:

    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        let translation = scrollView.panGestureRecognizer.translation(in: scrollView.superview)
        if translation.y > 0 {
            // swipes from top to bottom of screen -> down
        } else {
            // swipes from bottom to top of screen -> up
        }
    }
    

    And there you go. Again, if you need to track constantly, use Victors answer, otherwise I prefer this solution.

    0 讨论(0)
  • 2020-12-01 02:45

    I've found that this is the simplest and most flexible option (it works for UICollectionView and UITableView as well).

    override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    
        switch velocity {
        case _ where velocity.y < 0:
            // swipes from top to bottom of screen -> down
            trackingDirection = .down
        case _ where velocity.y > 0:
            // swipes from bottom to top of screen -> up
            trackingDirection = .up
        default: trackingDirection = .none
        }
    }
    

    Where this doesn't work though, is if there is 0 velocity - in which case you'll have no choice but to use the accepted answer's stored property solution.

    0 讨论(0)
  • 2020-12-01 02:45
    extension UIScrollView {
        enum ScrollDirection {
            case up, down, unknown
        }
        
        var scrollDirection: ScrollDirection {
            guard let superview = superview else { return .unknown }
            return panGestureRecognizer.translation(in: superview).y > 0 ? .down : .up
        }
    }
    
    0 讨论(0)
提交回复
热议问题