如何识别所有四个方向的滑动手势

143

我需要使用滑动手势识别向下和向右的滑动手势。但是在 Swift 中,UISwipeGestureRecognizer 拥有预设的向右方向...而我不知道如何使用其他方向。

20个回答

366

每个方向都需要一个UISwipeGestureRecognizer手势识别器。这有点奇怪,因为UISwipeGestureRecognizer.direction属性是一个选项式的位掩码,但每个手势识别器只能处理一个方向。如果你想的话,你可以把它们全部发送到同一个处理程序中,并在那里进行排序,或者将它们发送到不同的处理程序中。下面是一个实现示例:

override func viewDidLoad() {
    super.viewDidLoad()

    let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(respondToSwipeGesture))
    swipeRight.direction = .right
    self.view.addGestureRecognizer(swipeRight)

    let swipeDown = UISwipeGestureRecognizer(target: self, action: #selector(respondToSwipeGesture))
    swipeDown.direction = .down
    self.view.addGestureRecognizer(swipeDown)
}

@objc func respondToSwipeGesture(gesture: UIGestureRecognizer) {

    if let swipeGesture = gesture as? UISwipeGestureRecognizer {

        switch swipeGesture.direction {
        case .right:
            print("Swiped right")
        case .down:
            print("Swiped down")
        case .left:
            print("Swiped left")
        case .up:
            print("Swiped up")
        default:
            break
        }
    }
}

Swift 3:

override func viewDidLoad() {
    super.viewDidLoad()

    let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
    swipeRight.direction = UISwipeGestureRecognizerDirection.right
    self.view.addGestureRecognizer(swipeRight)

    let swipeDown = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
    swipeDown.direction = UISwipeGestureRecognizerDirection.down
    self.view.addGestureRecognizer(swipeDown)
}

func respondToSwipeGesture(gesture: UIGestureRecognizer) {
    if let swipeGesture = gesture as? UISwipeGestureRecognizer {
        switch swipeGesture.direction {
        case UISwipeGestureRecognizerDirection.right:
            print("Swiped right")
        case UISwipeGestureRecognizerDirection.down:
            print("Swiped down")
        case UISwipeGestureRecognizerDirection.left:
            print("Swiped left")
        case UISwipeGestureRecognizerDirection.up:
            print("Swiped up")
        default:
            break
        }
    }
}

每个识别器只能处理一个方向 - 这不是真的。请参见https://dev59.com/CnHYa4cB1Zd3GeqPKFRv - Sergey Skoblikov
5
"每个识别器只能处理一个方向" - 具体来说,在Swift中是正确的,在Objective-C中则是错误的。 - King-Wizard
13
您无需在.Down前面添加UISwipeGestureRecognizerDirection。只需使用swipeDown.direction = .Down即可。这是一个提示 =) - Paul Peelen
我们能否将相同的gestureRecogniser对象添加到多个视图中?我已经尝试过了,但没有成功。 - Max
3
如果你在 Swift 中使用 @Sergey Skoblikovs 的方法(通过 swipe.direction = [.Right,.Down,.Up,.Left]),识别器甚至不会被调用,这可能是 Swift 的一个问题,但就目前而言不起作用。 - Knight0fDragon
显示剩余4条评论

62

我只是想贡献一下,最终看起来更优雅:

func addSwipe() {
    let directions: [UISwipeGestureRecognizerDirection] = [.Right, .Left, .Up, .Down]
    for direction in directions {
        let gesture = UISwipeGestureRecognizer(target: self, action: Selector("handleSwipe:"))
        gesture.direction = direction
        self.addGestureRecognizer(gesture)
    }
}

func handleSwipe(sender: UISwipeGestureRecognizer) {
    print(sender.direction)
}

11
self.addGestureRecognizer(gesture) 对我来说引发了一个错误。解决方法是 self.view.addGestureRecognizer(gesture); - ahitt6345
1
@ahitt6345 我在一个 UIView 子类中使用了我的代码,但如果你在一个 UIViewController 中,你是完全正确的! - Alexandre Cassagne
1
干净,最适合我的答案。 - Christopher Smit

23

从故事板开始:

  1. 向您的视图添加四个滑动手势识别器。
  2. 在属性检查器中设置每一个手势的目标方向。您可以选择右、左、上或下。
  3. 逐一选择滑动手势识别器,控制+拖动到您的视图控制器。插入名称(假设为leftGesture、rightGesture、upGesture和downGesture),将连接更改为:Action,类型为:UISwipeGestureRecognizer。

从您的视图控制器开始:

@IBAction func rightGesture(sender: UISwipeGestureRecognizer) {
    print("Right")
}
@IBAction func leftGesture(sender: UISwipeGestureRecognizer) {
    print("Left")
}
@IBAction func upGesture(sender: UISwipeGestureRecognizer) {
    print("Up")
}

@IBAction func downGesture(sender: UISwipeGestureRecognizer) {
    print("Down")
}  

5
通过本答案,您不需要编写大量的代码,而是使用故事板和故事板与您的代码之间的连接。如果开发人员更喜欢以这种方式工作,这个答案可能更容易理解,但如果开发人员更喜欢在编码方面工作,那么第一个答案肯定是最好的。 - user3099333
我使用了4个滑动手势而不是一个,并且很多工作负载都在Storyboard中而不是编码中。 - user3099333

10

看起来最近情况有所变化。在 XCode 7.2 中,以下方法有效:

override func viewDidLoad() {
    super.viewDidLoad()

    let swipeGesture = UISwipeGestureRecognizer(target: self, action: "handleSwipe:")
    swipeGesture.direction = [.Down, .Up]
    self.view.addGestureRecognizer(swipeGesture)
}

func handleSwipe(sender: UISwipeGestureRecognizer) {
    print(sender.direction)
}

在iOS 8.4和9.2的模拟器上进行了测试并且在9.2的实际设备上进行了测试。

或者,可以使用mlcollard方便的扩展这里

let swipeGesture = UISwipeGestureRecognizer() {
    print("Gesture recognized !")
}

swipeGesture.direction = [.Down, .Up]
self.view.addGestureRecognizer(swipeGesture)

5
选择器可能会被调用,但发送者的方向不正确。换句话说,如果您不需要知道滑动的方向,那么这种方法是可以的,但如果需要知道方向,则不行。 - Robert Gummesson
不再起作用。在Swift 3中,必须向第一个值提供上下文:[UISwipeGestureRecognizerDirection.right, .left, .up, .down] - Brent Faust

7

Apple Swift 3.1版本 - Xcode 8.3版本(8E162)

以下是Alexandre Cassagne的方法:

let directions: [UISwipeGestureRecognizerDirection] = [.up, .down, .right, .left]
for direction in directions {
    let gesture = UISwipeGestureRecognizer(target: self, action: #selector(YourClassName.handleSwipe(gesture:)))
    gesture.direction = direction
    self.view?.addGestureRecognizer(gesture)   
}

func handleSwipe(gesture: UISwipeGestureRecognizer) {
    print(gesture.direction)
    switch gesture.direction {
    case UISwipeGestureRecognizerDirection.down:
        print("down swipe")
    case UISwipeGestureRecognizerDirection.up:
        print("up swipe")
    case UISwipeGestureRecognizerDirection.left:
        print("left swipe")
    case UISwipeGestureRecognizerDirection.right:
        print("right swipe")
    default:
        print("other swipe")
    }
}

1
使用此特定版本,您需要在终端中运行“defaults write com.apple.dt.xcode IDEPlaygroundDisableSimulatorAlternateFramebuffer -bool YES”以修复某些硬件上的错误。这个问题应该在新版本的Xcode中得到解决。 - Allison

6

在Swift 4.2和Xcode 9.4.1中

将动画委托CAAnimationDelegate添加到您的类中

//Swipe gesture for left and right
let swipeFromRight = UISwipeGestureRecognizer(target: self, action: #selector(didSwipeLeft))
swipeFromRight.direction = UISwipeGestureRecognizerDirection.left
menuTransparentView.addGestureRecognizer(swipeFromRight)

let swipeFromLeft = UISwipeGestureRecognizer(target: self, action: #selector(didSwipeRight))
swipeFromLeft.direction = UISwipeGestureRecognizerDirection.right
menuTransparentView.addGestureRecognizer(swipeFromLeft)

//Swipe gesture selector function
@objc func didSwipeLeft(gesture: UIGestureRecognizer) {
    //We can add some animation also
    DispatchQueue.main.async(execute: {
            let animation = CATransition()
            animation.type = kCATransitionReveal
            animation.subtype = kCATransitionFromRight
            animation.duration = 0.5
            animation.delegate = self
            animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
            //Add this animation to your view
            self.transparentView.layer.add(animation, forKey: nil)
            self.transparentView.removeFromSuperview()//Remove or hide your view if requirement.
        })
}

//Swipe gesture selector function
@objc func didSwipeRight(gesture: UIGestureRecognizer) {
        // Add animation here
        DispatchQueue.main.async(execute: {
            let animation = CATransition()
            animation.type = kCATransitionReveal
            animation.subtype = kCATransitionFromLeft
            animation.duration = 0.5
            animation.delegate = self
            animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
            //Add this animation to your view
            self.transparentView.layer.add(animation, forKey: nil)
            self.transparentView.removeFromSuperview()//Remove or hide yourview if requirement.
        })
}

如果您想从视图中删除手势,请使用以下代码:

如果您想从视图中删除手势,请使用以下代码

self.transparentView.removeGestureRecognizer(gesture)

示例:

func willMoveFromView(view: UIView) {
    if view.gestureRecognizers != nil {
        for gesture in view.gestureRecognizers! {
            //view.removeGestureRecognizer(gesture)//This will remove all gestures including tap etc...
            if let recognizer = gesture as? UISwipeGestureRecognizer {
                //view.removeGestureRecognizer(recognizer)//This will remove all swipe gestures
                if recognizer.direction == .left {//Especially for left swipe
                    view.removeGestureRecognizer(recognizer)
                }
            }
        }
    }
}

调用此函数的方式如下:

//Remove swipe gesture
self.willMoveFromView(view: self.transparentView)

像这样,您可以编写剩余的说明,请注意是否从底部到顶部或从顶部到底部具有滚动视图

如果有滚动视图,则在从上到下和相反方向手势中会发生冲突.


5

根据@Alexandre Cassagne的方法,使用Swift 5和XCode 11实现在视图或视图控制器中轻松切换视图,只需使用滑动手势即可。

override func viewDidLoad() {
    super.viewDidLoad()

    addSwipe()
}

func addSwipe() {
    let directions: [UISwipeGestureRecognizer.Direction] = [.right, .left, .up, .down]
    for direction in directions {
        let gesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe))
        gesture.direction = direction
        self.myView.addGestureRecognizer(gesture)// self.view
    }
}

@objc func handleSwipe(sender: UISwipeGestureRecognizer) {
    let direction = sender.direction
    switch direction {
        case .right:
            print("Gesture direction: Right")
        case .left:
            print("Gesture direction: Left")
        case .up:
            print("Gesture direction: Up")
        case .down:
            print("Gesture direction: Down")
        default:
            print("Unrecognized Gesture Direction")
    }
}

4

Swift 5+

为一些UIView添加所需的手势:

[UISwipeGestureRecognizer.Direction.up, .down, .left, .right].forEach {
    let gesture = UISwipeGestureRecognizer(target: self, action: #selector(swiped))
    gesture.direction = $0
    someView.addGestureRecognizer(gesture)
}

处理滑动操作:

@objc func swiped(_ gesture: UISwipeGestureRecognizer) {
    switch gesture.direction {
    case .up:       print("up")
    case .down:     print("down")
    case .left:     print("left")
    case .right:    print("right")
    default: break
    }
}

4

Swift 5中的滑动手势

  override func viewDidLoad() {
    super.viewDidLoad()
    let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
    swipeLeft.direction = .left
    self.view!.addGestureRecognizer(swipeLeft)

    let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
    swipeRight.direction = .right
    self.view!.addGestureRecognizer(swipeRight)

    let swipeUp = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
    swipeUp.direction = .up
    self.view!.addGestureRecognizer(swipeUp)

    let swipeDown = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
    swipeDown.direction = .down
    self.view!.addGestureRecognizer(swipeDown)
}

@objc func handleGesture(gesture: UISwipeGestureRecognizer) -> Void {
    if gesture.direction == UISwipeGestureRecognizer.Direction.right {
        print("Swipe Right")
    }
    else if gesture.direction == UISwipeGestureRecognizer.Direction.left {
        print("Swipe Left")
    }
    else if gesture.direction == UISwipeGestureRecognizer.Direction.up {
        print("Swipe Up")
    }
    else if gesture.direction == UISwipeGestureRecognizer.Direction.down {
        print("Swipe Down")
    }
}

4

UISwipeGestureRecognizer有一个direction属性,其定义如下:

var direction: UISwipeGestureRecognizerDirection

这个手势识别器允许的滑动方向。
Swift 3.0.1(及以下版本)的问题在于,即使UISwipeGestureRecognizerDirection符合OptionSet,以下代码片段也会编译但不会产生任何预期的积极结果:
// This compiles but does not work
let gesture = UISwipeGestureRecognizer(target: self, action: #selector(gestureHandler))
gesture.direction = [.right, .left, .up, .down]
self.addGestureRecognizer(gesture)

作为一种解决方法,你需要为每个所需的方向创建一个 UISwipeGestureRecognizer
以下 Playground 代码展示了如何使用数组的 map 方法为同一个 UIView 和相同的 selector 实现多个 UISwipeGestureRecognizer
import UIKit
import PlaygroundSupport

class SwipeableView: UIView {
    convenience init() {
        self.init(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
        backgroundColor = .red

        [UISwipeGestureRecognizerDirection.right, .left, .up, .down].map({
            let gesture = UISwipeGestureRecognizer(target: self, action: #selector(gestureHandler))
            gesture.direction = $0
            self.addGestureRecognizer(gesture)
        })
    }

    func gestureHandler(sender: UISwipeGestureRecognizer) {
        switch sender.direction {
        case [.left]:   frame.origin.x -= 10
        case [.right]:  frame.origin.x += 10
        case [.up]:     frame.origin.y -= 10
        case [.down]:   frame.origin.y += 10
        default:        break
        }
    }
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        view.addSubview(SwipeableView())
    }
}

let controller = ViewController()
PlaygroundPage.current.liveView = controller

同样的问题仍然存在于Xcode 8.3中 - 编译通过但不起作用 - 我只得到了左右两个方向的返回值 UISwipeGestureRecognizerDirection(rawValue: 15) - Johannes Knust

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接