ios 如何在 Swift 中获取 UIScrollView 垂直方向?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31857333/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 07:10:33  来源:igfitidea点击:

How to get UIScrollView vertical direction in Swift?

iosswiftcocoa-touchuiviewcontrolleruiscrollview

提问by user2722667

How can I get the scroll/swipe direction for up/down in a VC?

如何在 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 UIViewdepending if it was an up/down gesture.

我想在我的 VC 中添加一个 UIScrollView 或其他东西,它可以查看用户是否向上或向下滑动/滚动,然后隐藏/显示UIView取决于它是否是向上/向下手势。

回答by Victor Sigler

If you use an UIScrollViewthen 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:

如果您使用 anUIScrollView那么您可以从该scrollViewDidScroll:功能中受益。您需要保存contentOffset它拥有的最后一个位置 (the ) 并按以下方式更新它:

// 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.

我希望这对你有帮助。

回答by GLS

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:

Victor 的回答很好,但它非常昂贵,因为您总是在比较和存储值。如果您的目标是在不进行昂贵计算的情况下立即识别滚动方向,请尝试使用 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.

你去吧。同样,如果您需要不断跟踪,请使用 Victors 答案,否则我更喜欢此解决方案。

回答by gbotha

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.heightand then limiting the scrollView.contentOffset.yrange to be greater than 0 or less than scrollView.contentSize.height - scrollView.frame.height, no changes are made when bouncing back.

我使用了维克多的答案,但略有改进。当滚动超过滚动的结尾或开头时,然后获得反弹效果。我通过计算scrollView.contentSize.height - scrollView.frame.height然后将scrollView.contentOffset.y范围限制为大于 0 或小于 来添加约束,scrollView.contentSize.height - scrollView.frame.height弹回时不进行任何更改。

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
}

回答by Hardik Thakkar

For swift4

对于 swift4

Implement the scrollViewDidScrollmethod that detects when you pan gesture beyond a y-axis of 0:

实现scrollViewDidScroll检测何时平移手势超过 0 y 轴的方法:

public func scrollViewDidScroll(_ scrollView: UIScrollView) {

        if(scrollView.panGestureRecognizer.translation(in: scrollView.superview).y > 0) {
            print("up")
        }
        else {
            print("down")
        }
    }

回答by Petros Mitakos

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.

我已经尝试了这个线程中的每一个响应,但没有一个可以为启用了反弹的 tableView提供适当的解决方案。所以我只使用了部分解决方案以及一些历史悠久的经典布尔标志解决方案。

1) So, first of all you could use an enum for the scrollDirection:

1) 所以,首先你可以为 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:

2) 设置 3 个新的私有变量来帮助我们存储 lastOffset、scrollDirection 和一个标志来启用/禁用滚动方向计算(帮助我们忽略 tableView 的反弹效果),稍后您将使用它:

private var shouldCalculateScrollDirection = false
private var lastContentOffset: CGFloat = 0
private var scrollDirection: ScrollDirection = .up

3) In the scrollViewDidScrolladd the following:

3) 在scrollViewDidScroll添加以下内容:

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 scrollViewDidEndDraggingimplement it and add these lines of code inside it:

4) 如果你还没有实现scrollViewDidEndDragging实现它并在其中添加以下代码行:

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    guard !decelerate else { return }
    shouldCalculateScrollDirection = false
}

5) If you have not implemented scrollViewWillBeginDeceleratingimplement it and add this line of code inside it:

5) 如果你还没有实现scrollViewWillBeginDecelerating实现它并在里面添加这行代码:

func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
    shouldCalculateScrollDirection = false
}

6) Finally, If you have not implemented scrollViewWillBeginDraggingimplement it and add this line of code inside it:

6) 最后,如果你还没有实现scrollViewWillBeginDragging实现它并在里面添加这行代码:

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
}

回答by Daniel Krom

Swift 2-4 with UISwipeGestureRecognizer

Swift 2-4 与 UISwipeGestureRecognizer

Another option, is use to use the UISwipeGestureRecognizerthat will recognize the swipe to requested direction (That will work on all views and not only on UIScrollView

另一个选项,用于使用UISwipeGestureRecognizer将识别向请求方向滑动的 的(这将适用于所有视图,而不仅适用于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")
        }
    }
}

回答by Felipe Rolvar

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:

并使用 scrollViewDelegate:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    switch checkScrollDirection(scrollView) {
    case .up:
        // move up
    case .down:
        // move down
    default:
        break
    }

    lastContentOffset = scrollView.contentOffset
}

回答by brandonscript

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

我发现这是最简单和最灵活的选项(它也适用于 UICollectionView 和 UITableView)。

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 - 在这种情况下,您别无选择,只能使用已接受答案的存储属性解决方案。

回答by Sasho

For SwiftI 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 .lastDirectionscrolled property if you need to consult that in your code at any other stage.

对于 Swift,我认为最简单和最强大的就是像下面那样做。它允许您跟踪方向何时发生变化,并且仅在方向发生变化时做出反应。另外,.lastDirection如果您需要在任何其他阶段在代码中查阅该属性,您始终可以访问滚动属性。

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 .leftand .rightto track any direction.

以上假设您只跟踪向上/向下滚动。它可以通过枚举进行定制。您可以添加/更改.left.right跟踪任何方向。

I hope this helps someone.

我希望这可以帮助别人。

Cheers

干杯

回答by Changnam Hong

I made protocol to reuse Scroll Directions.

我制定了重用滚动方向的协议。

Declare these enumand protocols.

声明这些enumprotocols。

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

使用自 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 contentOffsetthat you want.

如果您想使用特定方向,只需更新contentOffset您想要的特定方向。