How to prevent one click function to be called within two click function?

最后都变了- 提交于 2019-12-14 04:13:43

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!