我有一个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")
}
}
答案 0 :(得分:1)
有趣。似乎正在发生的事情是在模态示例中,识别器状态从未从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(_:)))
...至少可以打印到“长”点。
警告:我建议您进行更多调查,因为我不知道是否会由于此覆盖而导致任何损坏。 (但指出了两种情况之间的差异。)
答案 1 :(得分:0)
由于@ phillip-mills的启发,我实现了“有效的” Recognizer
。
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"
}
}
}
但是,我的自定义手势子类的工作原理与 苹果的,它不与模式视图控制器一起使用。我也是 大胆猜测苹果还使用了
Timer
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 = 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)
}
}