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

时间:2015-08-06 13:38:45

标签: ios swift cocoa-touch uiviewcontroller uiscrollview

如何在VC中上/下滚动/滑动方向?

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

13 个答案:

答案 0 :(得分:70)

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

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

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

我希望这对你有所帮助。

答案 1 :(得分:36)

维克多的答案很棒,但它非常昂贵,因为你总是比较和存储价值观。如果你的目标是立即识别滚动方向而无需昂贵的计算,那么试试这个使用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
    }
}

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

答案 2 :(得分:8)

我用Victor的答案略有改进。滚动滚动结束或开始滚动,然后获得反弹效果。我通过计算inline然后将scrollView.contentSize.height - scrollView.frame.height范围限制为大于0或小于scrollView.contentOffset.y来添加约束,在弹回时不会进行任何更改。

scrollView.contentSize.height - scrollView.frame.height

答案 3 :(得分:2)

Swift 2-4 with UISwipeGestureRecognizer

另一个选项是使用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")
        }
    }
}

答案 4 :(得分:2)

适用于swift4

public func scrollViewDidScroll(_ scrollView: UIScrollView) {

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

答案 5 :(得分:1)

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

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

我希望这有助于某人。

干杯

答案 6 :(得分:1)

你可以这样做:

fileprivate var lastContentOffset: CGPoint = .zero

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

并使用scrollViewDelegate:

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

    lastContentOffset = scrollView.contentOffset
}

答案 7 :(得分:1)

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

def get_prices(portfolio: List[String], years: Range): List[List[Option[Double]]] = {
    var outerList = List[List[Option[Double]]]()
    for( j <- years) 
    {
        var innerList = List[Option[Double]]()
        for( i <- portfolio) 
            innerList ::= get_first_price(i, j) 

        outerList ::= innerList.reverse
    }
    outerList.reverse
}

虽然这不起作用,但是如果有0速度 - 在这种情况下你将别无选择,只能使用接受的答案的存储属性解决方案。

答案 8 :(得分:1)

我已经尝试了该线程中的每个响应,但没有一个可以为启用了跳动的tableView提供正确的解决方案。因此,我只使用了部分解决方案以及一些经典的布尔标志解决方案。

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

enum ScrollDirection {
    case up, down
}

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

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

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)如果尚未实现 scrollViewDidEndDragging ,请实现它,并在其中添加以下代码行:

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

5)如果尚未实现 scrollViewWillBeginDecelerating ,请实现它,并在其中添加以下代码行:

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

6)最后,如果尚未实现 scrollViewWillBeginDragging ,请实现它,并在其中添加以下代码行:

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

如果您按照上述所有步骤进行操作,那就太好了!

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

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

答案 9 :(得分:0)

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

声明这些enumprotocol s。

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

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

答案 10 :(得分:0)

只需将此方法添加到您的视图 控制器

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

答案 11 :(得分:0)

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

答案 12 :(得分:0)

我就是这样做的。它几乎适用于我尝试过的所有情况。

  1. 用户向上或向下滚动
  2. 用户在滚动时改变方向
  3. 用户不再拖拽。滚动视图继续滚动。
<块引用>
    var goingUp: Bool
    let velocity = scrollView.panGestureRecognizer.velocity(in: scrollView).y
    /// `Velocity` is 0 when user is not dragging.
    if (velocity == 0){
        goingUp = scrollView.panGestureRecognizer.translation(in: scrollView).y < 0
    } else {
        goingUp = velocity < 0
    }
相关问题