OS X でも 10.10 より GestureRecognizer が使えるようになりました。そこで、よせばいいのに NSClickGestureRecognizer を使ってみたいと思う人がいるかもしれません。その時にシングルクリックとダブルクリックでアプリの挙動を変えたい事もあるかもしれません。
そんな時にはシングルクリック用のNSClickGestureRecognizer とダブルクリック用のNSClickGestureRecognizer を実装すればいいと思うかもしれませんよね。
class MyViewController: NSViewController {
// 省略
override func viewDidLoad() {
super.viewDidLoad()
// 省略
let singleClickGesture = NSClickGestureRecognizer(target: self, action: "singleClickGesture:")
singleClickGesture.numberOfClicksRequired = 1 // single
self.view.addGestureRecognizer(singleClickGesture)
let doubleClickGesture = NSClickGestureRecognizer(target: self, action: "doubleClickGesture:")
doubleClickGesture.numberOfClicksRequired = 2 // double
self.view.addGestureRecognizer(doubleClickGesture)
}
// 省略
}
問題は、これでダブルクリックを行うと、シングルクリックとダブルクリックと両方のメソッドが呼ばれてしまいます。
func singleClickGesture(gesture: NSClickGestureRecognizer) {
if gesture.state == .Ended {
print("single click")
}
}
func doubleClickGesture(gesture: NSClickGestureRecognizer) {
if gesture.state == .Ended {
print("double click")
}
}
試しにダブルクリックしてみましょう。
single click
double click
iOSの場合は requireGestureRecognizerToFail
というメソッドが用意されていて、ダブルタップが失敗した時のみシングルタップを有効にできました。ところが OS X にはこの requireGestureRecognizerToFail
がありません。OS X は後発なのでこの辺頼みますよと言いたい所です。
singleTapGesture.requireGestureRecognizerToFail(doubleTapGesture)
Developer Forums にも質問はありますが、答えは出ていません(2016年1月現在)。
https://forums.developer.apple.com/thread/21347
さて気を取り戻して、delegate を調べてみる事にします。
optional func gestureRecognizer(_ gestureRecognizer: NSGestureRecognizer,
shouldRequireFailureOfGestureRecognizer otherGestureRecognizer: NSGestureRecognizer) -> Bool
Asks the delegate if the current gesture recognizer must wait to recognize its gesture until the specified gesture recognizer fails.
Return Value
YES if otherGestureRecognizer must fail before gestureRecognizer is allowed to recognize its gesture. If you do not implement this method, the default return value is NO.
Discussion
This method is called once per attempt to recognize, so you can change the failure requirements dynamically. The two gesture recognizers do not have to belong to the same view hierarchy.Returning YES is guaranteed to set up the failure requirement; returning NO does not prevent the failure requirement from being set up by the other gesture recognizer.
なんだか使えそうな予感がします。これで、シングルクリックはダブルクリックが失敗した場合のみ有効とできそうですね。ちゃんと delegate が設定されているかどうか確認してください。
class MyViewController: NSViewController, NSGestureRecognizerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// some code
let singleClickGesture = NSClickGestureRecognizer(target: self, action: "singleClickGesture:")
singleClickGesture.numberOfClicksRequired = 1 // single
singleClickGesture.delegate = self
self.view.addGestureRecognizer(singleClickGesture)
let doubleClickGesture = NSClickGestureRecognizer(target: self, action: "doubleClickGesture:")
doubleClickGesture.numberOfClicksRequired = 2 // double
doubleClickGesture.delegate = self
self.view.addGestureRecognizer(doubleClickGesture)
}
func gestureRecognizer(_ gestureRecognizer: NSGestureRecognizer, shouldRequireFailureOfGestureRecognizer otherGestureRecognizer: NSGestureRecognizer) -> Bool {
if let gestureRecognizer1 = gestureRecognizer as? NSClickGestureRecognizer,
let gestureRecognizer2 = otherGestureRecognizer as? NSClickGestureRecognizer
where gestureRecognizer1.numberOfClicksRequired == 1 &&
gestureRecognizer2.numberOfClicksRequired == 2 {
return true
}
return false
}
// 省略
}
試しにダブルクリックしてみましょう。
double click
では今度はシングルクリック
single click
これで、うまくダブルクリックとシングルクリックを識別できるようになりました。