如何取消 LongPressGestureRecognizer?

How to cancel LongPressGestureRecognizer?

我有一个分配了 LongPressGestureRecognizer 的视图,它调用以下方法:

@IBAction func longPressOnView1Recognized(_ sender: UIGestureRecognizer) {

    if sender.state == .began {
        // this runs when user's finger is down a "long time"
    }
    if sender.state == .ended {
        // this runs when user's finger goes up again after the .began state 
    }

}

这一切都按预期工作,但我正在尝试找到一种 (good/proper) 方式,能够以编程方式 cancel 长按识别器(在某些情况下),同时用户的手指还在下

也就是说,while用户的手指还在view上,识别器进入了.began状态,(但是before 用户已经抬起手指——在识别器进入 .ended 状态之前)...是否有一些代码我们可以 运行 来防止上述方法在用户抬起手指时触发...比如过早地告诉 IOS 在这个手势的剩余部分不再监听 UP 事件?

我读过这些 docs,但我对 IOS 触摸没有那么多经验,而且我似乎找不到任何为此目的而设计的方法。

我的 GestureRecognizer.reset() 似乎与我描述的不符。

我想到了两种可能:

1) 一个布尔标志,将进入 if sender.state == .ended {} 闭包

2) 这个:

myLongPressRecognizer.isEnabled = false
myLongPressRecognizer.isEnabled = true

这两个都有效,但似乎不太好。

您已经有了解决方案。切换 UILongPressGestureRecognizer isEnabled 是最好的方法。设置 state 属性 是不可能的,因为它是一个 get-only 属性.

open var state: UIGestureRecognizer.State { get } // the current state of the gesture recognizer

isEnabled 属性 记录为:

default is YES. disabled gesture recognizers will not receive touches. when changed to NO the gesture recognizer will be cancelled if it's currently recognizing a gesture.

你们都很擅长禁用和重新启用手势识别器

myLongPressRecognizer.isEnabled = false
myLongPressRecognizer.isEnabled = true

完全正确。

我担心的是你不完全理解手势识别器。在处理手势识别器时,您应该始终使用 switch 语句。查看评论:

func handleLongPressGestureRecognizer(_ sender: UIGestureRecognizer) {

    switch sender.state {
    case .began:
        // This will be called only once when the gesture starts
        print("Long press did begin at \(sender.location(in: sender.view))")
    case .changed:
        // This will be called whenever your finger moves (at some frequency obviously).
        // At this point your long press gesture is acting exactly the same as pan gesture
        print("Long press changed position to \(sender.location(in: sender.view))")
    case .ended:
        // This is when user lifts his finger assuming the gesture was not canceled
        print("Long press ended at \(sender.location(in: sender.view))")
    case .cancelled:
        // This is equally important as .ended case. You gesture may be canceled for many reasons like a system gesture overriding it. Make sure to implement logic here as well.
        print("Long press canceled at \(sender.location(in: sender.view))")
    case .failed, .possible:
        // These 2 have been added additionally at some point. Useless as far I am concerned.
        break
    }

}

所以至少你应该处理取消状态。但还要注意,只要移动手势,就会触发更改的状态。

您可以导入手势识别器header:

import UIKit.UIGestureRecognizer

这将使 state 属性 成为读写 属性。因此,要取消手势,只需将其 state 更改为 .cancelled.

因此,例如,您可以在识别长按手势识别器一秒后取消它,例如:

weak var timer: Timer?

@objc func handleLongPress(_ gesture: UILongPressGestureRecognizer) {
    switch gesture.state {
    case .began:
        print("began")
        timer?.invalidate()
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in
            gesture.state = .cancelled
        }

    case .ended, .cancelled:
        print(gesture.state == .ended ? "Ended" : "Cancelled")
        timer?.invalidate()

    default:
        break
    }
}