web-dev-qa-db-ja.com

SwiftでUIScrollViewの垂直方向を取得する方法は?

VCで上下のスクロール/スワイプの方向を取得するにはどうすればよいですか?

UIScrollViewなどをVCに追加して、ユーザーが上下にスワイプ/スクロールしたかどうかを確認し、それがアップかどうかに応じてUIViewを非表示/表示できるようにします。 /ダウンジェスチャー。

24
user2722667

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
}

もちろん、これを行う方法は他にもあります。

これがお役に立てば幸いです。

75
Victor Sigler

ビクターの答えは素晴らしいですが、値を常に比較して保存しているため、非常に高価です。あなたの目標が高価な計算なしでスクロール方向を即座に特定することであるなら、これを試してください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 answerを使用してください。 ????

38
GLS

ビクターの答えを少し改善して使用しました。スクロールの終わりまたは始まりを過ぎてスクロールし、バウンスバック効果を得るとき。 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
}
9
gbotha

Swift4の場合

public func scrollViewDidScroll(_ scrollView: UIScrollView) {

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

UISwipeGestureRecognizerを使用したSwift 2-4

別のオプションは、要求された方向へのスワイプを認識する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")
        }
    }
}
2
Daniel Krom

私はこのスレッドですべての単一の応答を試しましたが、それらのどれも適切なバウンスを有効にした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
}
2
Petros Mitakos

これが最も簡単で柔軟なオプションであることがわかりました(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
    }
}

これが機能しないのは、速度が0の場合です。この場合、受け入れられた回答の保存プロパティソリューションを使用する以外に選択肢はありません。

2
brandonscript

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

上記は、上下スクロールのみを追跡していることを前提としています。 enumを介してカスタマイズできます。 .leftおよび.rightを追加/変更して、あらゆる方向を追跡できます。

これが誰かの役に立つことを願っています。

乾杯

1
Sasho

次のようなことができます:

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
}
1
Felipe Rolvar

Scroll Directionsを再利用するプロトコルを作成しました。

これらのenumおよび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
    }
}

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を更新するだけです。

0
Changnam Hong

このメソッドをviewcontrollerに追加するだけです:

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)
    }
}
0
Archi Stepanov