8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

NSClickGestureRecognizer でシングルクリックとダブルクリックを識別

Last updated at Posted at 2016-01-04

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

これで、うまくダブルクリックとシングルクリックを識別できるようになりました。

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?