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

问题描述 投票:30回答:11

如何获得VC中向上/向下的滚动/滑动方向?

我想在我的VC中添加一个UIScrollView或其他内容,以查看用户是否向上/向下滑动/滚动,然后根据其是向上/向下手势来隐藏/显示UIView

ios swift cocoa-touch uiviewcontroller uiscrollview
11个回答
83
投票

如果使用UIScrollView,则可以从scrollViewDidScroll:功能中受益。您需要保存它的最后一个位置(scrollViewDidScroll:)并按照以下方式进行更新:

contentOffset

当然还有其他方法可以做到这一点。

希望对您有帮助。


0
投票
我制定了协议以重用滚动方向。

声明这些func scrollViewDidScroll(_ scrollView: UIScrollView) { switch checkScrollDirection(scrollView) { case .up: // move up case .down: // move down default: break } lastContentOffset = scrollView.contentOffset } enum

protocol

来自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
    }
}
的使用

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
        }
    }

0
投票
只需将此方法添加到您的

view controller

contentOffset

51
投票

维克多的答案很好,但价格昂贵,因为您一直在比较和存储值。如果您的目标是无需昂贵的计算即可立即确定滚动方向,请尝试使用此[[using Swift:

// 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 }
然后你去。同样,如果您需要不断跟踪,请使用Victors答案,否则我更喜欢这种解决方案。 😊

13
投票
我使用维克多的答案做了微小的改进。当滚动超过滚动的末尾或开始时,然后获得回弹效果。通过计算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 } } ,然后将scrollView.contentSize.height - scrollView.frame.height范围限制为大于0或小于scrollView.contentOffset.y,我添加了约束,弹回时不会进行任何更改。

scrollView.contentSize.height - scrollView.frame.height


7
投票

对于swift4

实现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 } 方法,该方法可检测到您平移手势的y轴超出0:]

scrollViewDidScroll


5
投票
我已经尝试了该线程中的每个响应,但是没有一个可以提供正确的

启用了跳动的tableView解决方案。因此,我只使用了部分解决方案以及一些历史悠久的经典布尔标志解决方案。

1)因此,首先,您可以为scrollDirection使用一个枚举:

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

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

enum ScrollDirection { case up, down }

3)在

scrollViewDidScroll中添加以下内容:

private var shouldCalculateScrollDirection = false private var lastContentOffset: CGFloat = 0 private var scrollDirection: ScrollDirection = .up
4)如果尚未实现

scrollViewDidEndDragging,请实施并在其中添加以下代码行:

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 }
5)如果尚未实现

scrollViewWillBeginDecelerating,请实现它并在其中添加以下代码行:

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { guard !decelerate else { return } shouldCalculateScrollDirection = false }
6)最后,如果尚未实现

scrollViewWillBeginDragging,请实现它,并在其中添加以下代码行:

func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) { shouldCalculateScrollDirection = false }
如果您按照上述所有步骤操作,那就太好了!

您可以去任何要使用此方向的地方,只需写:

func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { shouldCalculateScrollDirection = true }


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

switch scrollDirection { case .up: // Do something for scollDirection up case .down: // Do something for scollDirection down }

但是如果速度为0,则无法使用-在这种情况下,您别无选择,只能使用接受的答案的存储属性解决方案。

2
投票
使用UISwipeGestureRecognizer的Swift 2-4

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

UIScrollView


1
投票

For Swift我认为最简单,最强大的方法是执行以下操作。它允许您跟踪方向更改的时间,并且仅在更改方向时做出反应。另外,如果需要在其他任何阶段在代码中进行查询,则始终可以访问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") } } } 滚动属性。

.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
            }
        }
    }
}
.left以跟踪任何方向。

我希望这对某人有帮助。

欢呼声


1
投票
您可以做这样的事情:

.right

和scrollViewDelegate:

fileprivate var lastContentOffset: CGPoint = .zero func checkScrollDirection(_ scrollView: UIScrollView) -> UIScrollViewDirection { return lastContentOffset.y > scrollView.contentOffset.y ? .up : .down }

© www.soinside.com 2019 - 2024. All rights reserved.