问题
I am trying to add custom behaviour to my buttons. If clicked once - one action is performed. If clicked twice another one is performed.
I saw such a solution in this answer and I have tried all possible combinations:
clickOnce.shouldBeRequiredToFailByGestureRecognizer(clickTwice)
clickTwice.shouldBeRequiredToFailByGestureRecognizer(clickOnce)
clickOnce.shouldRequireFailureOfGestureRecognizer(clickTwice)
clickTwice.shouldRequireFailureOfGestureRecognizer(clickOnce)
clickOnce.canPreventGestureRecognizer(clickTwice)
clickOnce.canBePreventedByGestureRecognizer(clickTwice)
clickTwice.canPreventGestureRecognizer(clickOnce)
clickTwice.canBePreventedByGestureRecognizer(clickOnce)
But nothing worked for me.
And here's the full code:
import Cocoa
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let buttonTestOne = NSButton(frame: CGRect(x: 500, y: 500, width: 100, height: 500))
let clickOnceForTestOne = NSClickGestureRecognizer(target: buttonTestOne, action: #selector(ViewController.clickOneTime(_:)))
clickOnceForTestOne.numberOfClicksRequired = 1
buttonTestOne.addGestureRecognizer(clickOnceForTestOne)
self.view.addSubview(buttonTestOne)
let arrTestButtons = ["One", "Two", "Three"]
var x = 0
var y = 0
for item in arrTestButtons{
let buttonNew = NSButton(frame: CGRect(x: x, y: y, width: 100, height: 100))
x = x + 120
y = y + 120
buttonNew.attributedTitle = NSAttributedString(string: item)
let clickOnce = NSClickGestureRecognizer(target: self, action: #selector(ViewController.clickOneTime(_:)))
clickOnce.numberOfClicksRequired = 1
buttonNew.addGestureRecognizer(clickOnce)
let clickTwice = NSClickGestureRecognizer(target: self, action: #selector(ViewController.clickTwoTimes(_:)))
clickTwice.numberOfClicksRequired = 2
buttonNew.addGestureRecognizer(clickTwice)
clickOnce.shouldBeRequiredToFailByGestureRecognizer(clickTwice)
clickTwice.shouldBeRequiredToFailByGestureRecognizer(clickOnce)
clickOnce.shouldRequireFailureOfGestureRecognizer(clickTwice)
clickTwice.shouldRequireFailureOfGestureRecognizer(clickOnce)
clickOnce.canPreventGestureRecognizer(clickTwice)
clickOnce.canBePreventedByGestureRecognizer(clickTwice)
clickTwice.canPreventGestureRecognizer(clickOnce)
clickTwice.canBePreventedByGestureRecognizer(clickOnce)
self.view.addSubview(buttonNew)
}
}
func clickOneTime(g:NSClickGestureRecognizer){
if g.state == .Ended {
Swift.print("single click")
}
}
func clickTwoTimes(g: NSClickGestureRecognizer){
if g.state == .Ended {
Swift.print("DOUBLE CLICK!")
}
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
}
What am I doing wrong? I think the mistake must be pretty simple, I am either calling from the wrong place, or somewhat like that, but I can't understand.
Here is the log file, which is the same for all combinations:
Clicked once:
single click
As expected
Clicked twice:
single click
DOUBLE CLICK!
Which starts both single and double click.
I have read the documentation. And I've tried all the combinations, because couldn't find a solution.
I have also tried with the logs. So Swift.print(clickOnce.shouldBeRequiredToFailByGestureRecognizer(clickTwice))
and one of these, but it gives me false
.
回答1:
Try this:
let click = NSClickGestureRecognizer(target: self, action: #selector(clicked(_:))
click.numberOfClicksRequired = 2
回答2:
I was trying to solve this myself; it turns out that the solution is relatively straightforward.
Use a gesture recogniser for the double-click (here, I've added them to the view, but the same principle should work for buttons)
let doubleClickRecognizer = NSClickGestureRecognizer(target: self, action: #selector(ViewController.clickTwice))
doubleClickRecognizer.numberOfClicksRequired = 2
self.view?.addGestureRecognizer(doubleClickRecognizer)
Add
@objc func clickTwice() {
print("double click")
}
and then handle single clicks through
override func mouseDown(with event: NSEvent) {
print("mouse down; once")
}
(or appropriate equivalent).
NSGestureRecognizer has
var delaysPrimaryMouseButtonEvents: Bool
which by default is set to true, so with this combination, it waits until the doubleClickRecognizer has handled the double-click before going up the responder chain to see who else is interested in a mouseclick.
Two gesture recognisers have the same problem as handling single and double clicks in mouseDown: the single click fires first. In order to overcome this, you need to override
func gestureRecognizer(_ gestureRecognizer: NSGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: NSGestureRecognizer) -> Bool
This is not a function you call, it's a delegate function that you override. So you set your viewController to conform to NSGestureRecognizerDelegate (which means it will receive delegate methods); set singleClickRecognizer.delegate = self (where self is your viewController), and implement
func gestureRecognizer(_ gestureRecognizer: NSGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: NSGestureRecognizer) -> Bool {
if gestureRecognizer == singleClickRecognizer && otherGestureRecognizer == doubleClickRecognizer {
return true
}
return false
}
which states that your singleClickRecognizer waits for the doubleClickRecognizer to fail before executing its selector.
Unfortunately, I have found that in SpriteKit, while this code does what it says on the tin (process a double-click first), it leads to unacceptable delays, so I'm not sure I can recommend it.
回答3:
Maybe you could try it this way, where "button" is your button
let doubleTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.clickTwoTimes(_:)))
let singleTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.clickOneTime(_:)))
singleTapRecognizer.numberOfTapsRequired = 1
doubleTapRecognizer.numberOfTapsRequired = 2
button.addGestureRecognizer(doubleTapRecognizer)
button.addGestureRecognizer(singleTapRecognizer)
singleTapRecognizer.requireGestureRecognizerToFail(doubleTapRecognizer)
来源:https://stackoverflow.com/questions/37238141/how-to-prevent-one-click-function-to-be-called-within-two-click-function