NSPressGestureRecognizer 在 modal ViewController 中不起作用



我有一个NSViewController的子类,里面有一个视图,它添加了一个NSPressGestureRecognizer。

如果我在StoryboardSegue中将ViewController显示为显示样式,NSPressGestureRecognizer就可以工作了。如果我在 StoryboardSegue 中将 ViewController 显示为模态样式,NSPressGestureRecognizer 不起作用。

知道如何解决这个问题吗?

import Cocoa
class VC: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let view = NSView(frame: NSRect(x: 100, y: 100, width: 100, height: 100))
view.wantsLayer = true
view.layer?.backgroundColor = NSColor.systemBrown.cgColor
let longPress = NSPressGestureRecognizer(target: self, action: #selector(longPress(_:)))
view.addGestureRecognizer(longPress)
self.view.addSubview(view)
}
@objc func longPress(_ sender:Any) {
print("long")
}
}

有趣。 似乎正在发生的事情是,在模式示例中,识别器状态永远不会从possible更改为began

创建此...

class Recognizer: NSPressGestureRecognizer {
override func mouseDown(with event: NSEvent) {
super.mouseDown(with: event)
self.state = .began
}
}

。并将代码的一行修改为...

let longPress = Recognizer(target: self, action: #selector(longPress(_:)))

。至少工作到打印"长"的地步。

警告:我建议进行更多调查,因为我不知道是否会因此覆盖而中断任何内容。 (但它指出了两种情况之间不同的区域。

我实现了"工作"Recognizer,这要归功于@phillip磨坊的启发。

import Cocoa
class VC: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let view = NSView(frame: NSRect(x: 100, y: 100, width: 100, height: 100))
view.wantsLayer = true
view.layer?.backgroundColor = NSColor.systemBrown.cgColor
let longPress = MyPressGestureRecognizer(target: self, action: #selector(longPress(_:)))
view.addGestureRecognizer(longPress)
let click = NSClickGestureRecognizer(target: self, action: #selector(click(_:)))
view.addGestureRecognizer(click)
self.view.addSubview(view)
}
@objc func click(_ sender:Any) {
print("click")
}
@objc func longPress(_ sender:Any) {
guard let gesture = sender as? NSGestureRecognizer else { return }
switch gesture.state {
case .ended:
print("long")
default:
print(gesture.state)
}
}
}
class MyPressGestureRecognizer: NSPressGestureRecognizer {
private weak var timer:Timer? = nil
private var hasBegan = false
private var hasCancelled = false
override func mouseDown(with event: NSEvent) {
super.mouseDown(with: event)
timer = Timer.scheduledTimer(withTimeInterval: minimumPressDuration, repeats: false) { (timer) in
defer {
timer.invalidate()
}
DispatchQueue.main.async {
self.state = .began
self.hasBegan = true
}
}
}
override func mouseUp(with event: NSEvent) {
if hasBegan {
self.state = .ended
self.hasBegan = false
}
super.mouseUp(with: event)
}
override func reset() {
timer?.invalidate()
super.reset()
}
}
extension NSGestureRecognizer.State:CustomStringConvertible {
public var description:String {
switch self {
case .possible:
return "possible"
case .began:
return "began"
case .changed:
return "changed"
case .ended:
return "ended"
case .cancelled:
return "cancelled"
case .failed:
return "failed"
@unknown default:
return "default"
}
}
}

但是,我的自定义手势子类的工作方式与 苹果的,它不与模态视图控制器一起工作。所以我是 大胆猜测苹果也使用了导致TimerNSPressGestureRecognizer在模式视图控制器中不起作用。

这是工作代码。

import Cocoa
class VC: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let view = NSView(frame: NSRect(x: 100, y: 100, width: 100, height: 100))
view.wantsLayer = true
view.layer?.backgroundColor = NSColor.systemBrown.cgColor
let longPress = MyPressGestureRecognizer(target: self, action: #selector(longPress(_:)))
view.addGestureRecognizer(longPress)
let click = NSClickGestureRecognizer(target: self, action: #selector(click(_:)))
view.addGestureRecognizer(click)
self.view.addSubview(view)
}
@objc func click(_ sender:Any) {
print("click")
}
@objc func longPress(_ sender:Any) {
guard let gesture = sender as? NSGestureRecognizer else { return }
switch gesture.state {
case .ended:
print("long")
default:
print(gesture.state)
}
}
}
class MyPressGestureRecognizer: NSPressGestureRecognizer {
private var hasBegan = false
private var hasCancelled = false
override func mouseDown(with event: NSEvent) {
super.mouseDown(with: event)
hasCancelled = false
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(Int(minimumPressDuration * 1000))) {
if !self.hasCancelled {
self.state = .began
self.hasBegan = true
}
}
}
override func mouseUp(with event: NSEvent) {
if hasBegan {
self.state = .ended
self.hasBegan = false
} else {
self.hasCancelled = true
}
super.mouseUp(with: event)
}
override func reset() {
super.reset()
}
}
extension NSGestureRecognizer.State:CustomStringConvertible {
public var description:String {
switch self {
case .possible:
return "possible"
case .began:
return "began"
case .changed:
return "changed"
case .ended:
return "ended"
case .cancelled:
return "cancelled"
case .failed:
return "failed"
@unknown default:
return "default"
}
}
}

我将另一个答案标记为已接受,以感谢对这个答案的启发。

---------使用调度源计时器更新---------------

class MyPressGestureRecognizer: NSPressGestureRecognizer {
private var hasBegan = false
private var timer:DispatchSourceTimer? = nil
override func mouseDown(with event: NSEvent) {
super.mouseDown(with: event)
let timer = DispatchSource.makeTimerSource()
timer.schedule(deadline: .now() + .milliseconds(Int(minimumPressDuration * 1000)))
timer.setEventHandler {
self.state = .began
self.hasBegan = true
}
timer.activate()
self.timer = timer
}
override func mouseUp(with event: NSEvent) {
if hasBegan {
self.state = .ended
self.hasBegan = false
} else {
self.timer?.cancel()
}
super.mouseUp(with: event)
}
}

最新更新