VCで上下のスクロール/スワイプの方向を取得するにはどうすればよいですか?
UIScrollViewなどをVCに追加して、ユーザーが上下にスワイプ/スクロールしたかどうかを確認し、それがアップかどうかに応じてUIView
を非表示/表示できるようにします。 /ダウンジェスチャー。
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
}
もちろん、これを行う方法は他にもあります。
これがお役に立てば幸いです。
ビクターの答えは素晴らしいですが、値を常に比較して保存しているため、非常に高価です。あなたの目標が高価な計算なしでスクロール方向を即座に特定することであるなら、これを試してください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を使用してください。 ????
ビクターの答えを少し改善して使用しました。スクロールの終わりまたは始まりを過ぎてスクロールし、バウンスバック効果を得るとき。 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
}
Swift4の場合
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
if(scrollView.panGestureRecognizer.translation(in: scrollView.superview).y > 0) {
print("up")
}
else {
print("down")
}
}
別のオプションは、要求された方向へのスワイプを認識する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")
}
}
}
私はこのスレッドですべての単一の応答を試しましたが、それらのどれも適切なバウンスを有効にした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
}
これが最も簡単で柔軟なオプションであることがわかりました(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の場合です。この場合、受け入れられた回答の保存プロパティソリューションを使用する以外に選択肢はありません。
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
を追加/変更して、あらゆる方向を追跡できます。
これが誰かの役に立つことを願っています。
乾杯
次のようなことができます:
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
}
Scroll Directionsを再利用するプロトコルを作成しました。
これらのenum
およびprotocol
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
を更新するだけです。
このメソッドを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)
}
}