Как получить вертикальное направление UIScrollView в Swift?
Как я могу получить направление прокрутки / салфетки для вверх / вниз в VC?
Я хочу добавить UIScrollView или что-то еще в моем VC, который может видеть, если пользователь проводит/прокручивает вверх или вниз, а затем скрывает/показывает UIView
в зависимости от того, был ли это жест вверх/вниз.
9 ответов
если вы используете UIScrollView
тогда вы можете воспользоваться scrollViewDidScroll:
ответ Виктора отличный, но он довольно дорогой, так как вы всегда сравниваете и сохраняете значения. Если ваша цель-мгновенно определить направление прокрутки без дорогостоящего расчета, попробуйте это использование 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.высота-scrollView.рамка.высота), а затем ограничение scrollView.contentOffset.диапазон y должен быть больше 0 или меньше (scrollView.contentSize.высота-scrollView.рамка.высота), никакие никакие изменения не сделаны отскакивая назад.
//code
if(self.lastContentOffset > scrollView.contentOffset.y) &&
self.lastContentOffset < (scrollView.contentSize.height - scrollView.frame.height) {
// move up
buttonAdd.hidden = false
}
else if (self.lastContentOffset < scrollView.contentOffset.y
&& scrollView.contentOffset.y > 0) {
// move down
buttonAdd.hidden = true
}
// update the new position acquired
self.lastContentOffset = scrollView.contentOffset.y`
Swift 2-4 С 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")
}
}
}
Для 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
отслеживать направление.
надеюсь, это кому-то поможет.
Ура
вы можете сделать что-то вроде этого:
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
}
Я обнаружил, что это самый простой и гибкий вариант (он также работает для 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 скорость - в этом случае у вас не будет выбора, кроме как использовать решение сохраненных свойств принятого ответа.
Я сделал протокол для повторного использования направлений прокрутки.
объявить эти 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
}
}
если вы хотите использовать конкретное направление, просто обновите specific contentOffset
что вы хотите.
для swift4
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
if(scrollView.panGestureRecognizer.translation(in: scrollView.superview).y > 0) {
print("up")
}
else {
print("down")
}
}