按住“重复点火”button

我已经提到了关于一个按住button的无数其他问题,但与Swift没有太多关系。 我有一个使用touchUpInside事件连接到button的function:

@IBAction func singleFire(sender: AnyObject){ //code } 

…和另一个function,意思是在按住同一个button的同时重复调用上述function,而在不再按下该button时停止:

 @IBAction func speedFire(sender: AnyObject){ button.addTarget(self, action: "buttonDown:", forControlEvents: .TouchDown) button.addTarget(self, action: "buttonUp:", forControlEvents: .TouchUpOutside) func buttonDown(sender: AnyObject){ timer = NSTimer.scheduledTimerWithTimeInterval(0.3, target: self, selector: "singleFire", userInfo: nil, repeats: true) } func buttonUp(sender: AnyObject){ timer.invalidate() } } 

我不知道我做错了什么,我不知道如何设置触摸事件到不同的function相同的button。

按住button时,您希望快速重复点火。

你的buttonDownbuttonUp方法需要在顶层定义,而不是在另一个函数内部。 出于演示的目的,放弃从故事板中@IBAction并且只需在viewDidLoad设置button@IBAction清楚了:

 class ViewController: UIViewController { @IBOutlet weak var button: UIButton! var timer: NSTimer! var speedAmmo = 100 func buttonDown(sender: AnyObject) { singleFire() timer = NSTimer.scheduledTimerWithTimeInterval(0.3, target: self, selector: "rapidFire", userInfo: nil, repeats: true) } func buttonUp(sender: AnyObject) { timer.invalidate() } func singleFire() { print("bang!") } func rapidFire() { if speedAmmo > 0 { speedAmmo-- print("bang!") } else { print("out of speed ammo, dude!") timer.invalidate() } } override func viewDidLoad() { super.viewDidLoad() // These could be added in the Storyboard instead if you mark // buttonDown and buttonUp with @IBAction button.addTarget(self, action: "buttonDown:", forControlEvents: .TouchDown) button.addTarget(self, action: "buttonUp:", forControlEvents: [.TouchUpInside, .TouchUpOutside]) } } 

另外,我将.TouchUpOutside更改为[.TouchUpInside, .TouchUpOutside] (同时捕获触摸事件),并在初始buttonDown上调用singleFire进行单次触发。 随着这些改变,按下button立即触发,然后每0.3秒触发一次,直到按下button。


该button可以在Storyboard中连线,而不是在viewDidLoad中设置。 在这种情况下,将@IBAction添加到buttonDownbuttonUp 。 然后按住Control键,在Storyboard上点击button,然后从Touch Down旁边的圆圈拖动到func buttonDown ,然后从Touch Up InsideOutside Up Outside旁边的圆圈拖动到func buttonUp

在这里输入图像说明

在我最初的回答中,我回答了如何让一个button同时识别水龙头和长按的问题。 在澄清的问题中,似乎只要用户按住手指,就希望此button能够持续“启动”。 如果是这种情况,则只需要一个手势识别器。

例如,在Interface Builder中,将一个长按手势识别器从对象库拖到button上,然后将“Min Duration”设置为零:

在这里输入图像说明

然后,您可以在助手编辑器中控制从长按手势识别器到您的代码,并添加@IBAction来处理长按:

 var timer: NSTimer? @IBAction func longPressHandler(gesture: UILongPressGestureRecognizer) { if gesture.state == .Began { timer = NSTimer.scheduledTimerWithTimeInterval(0.3, target: self, selector: "handleTimer:", userInfo: nil, repeats: true) } else if gesture.state == .Ended || gesture.state == .Cancelled { timer?.invalidate() timer = nil } } func handleTimer(timer: NSTimer) { NSLog("bang") } 

或者,如果您还想在用户将手指从button上拉开时停止触发,请添加手势位置检查:

 @IBAction func longPressHandler(gesture: UILongPressGestureRecognizer) { if gesture.state == .Began { timer = NSTimer.scheduledTimerWithTimeInterval(0.3, target: self, selector: "handleTimer:", userInfo: nil, repeats: true) } else if gesture.state == .Ended || gesture.state == .Cancelled || (gesture.state == .Changed && !CGRectContainsPoint(gesture.view!.bounds, gesture.locationInView(gesture.view))) { timer?.invalidate() timer = nil } } 

我的原始答案,回答了如何识别button和按下button的不同问题如下:


就我个人而言,我会使用轻按和长按手势识别器,例如:

 override func viewDidLoad() { super.viewDidLoad() let longPress = UILongPressGestureRecognizer(target: self, action: "handleLongPress:") button.addGestureRecognizer(longPress) let tap = UITapGestureRecognizer(target: self, action: "handleTap:") tap.requireGestureRecognizerToFail(longPress) button.addGestureRecognizer(tap) } func handleTap(gesture: UITapGestureRecognizer) { print("tap") } func handleLongPress(gesture: UILongPressGestureRecognizer) { if gesture.state == .Began { print("long press") } } 

如果你想用长按手势,你也可以在.Ended执行你的动作。 这只取决于所需的用户体验。

仅供参考,您也可以在界面生成器中添加这两个手势识别器(只需将各自的手势从对象库拖到button上,然后从手势识别器控制 -drag到@IBAction函数),但是更容易通过程序展示来说明正在发生的事情。

我更新了@vacawama示例代码swift 3.谢谢。

 @IBOutlet var button: UIButton! var timer: Timer! var speedAmmo = 100 @IBAction func buttonDown(sender: AnyObject) { singleFire() timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector:#selector(rapidFire), userInfo: nil, repeats: true) } @IBAction func buttonUp(sender: AnyObject) { timer.invalidate() } func singleFire() { if speedAmmo > 0 { speedAmmo -= 1 print("bang!") } else { print("out of speed ammo, dude!") timer.invalidate() } } func rapidFire() { if speedAmmo > 0 { speedAmmo -= 1 print("bang!") } else { print("out of speed ammo, dude!") timer.invalidate() } } override func viewDidLoad() { super.viewDidLoad() button.addTarget(self, action:#selector(buttonDown(sender:)), for: .touchDown) button.addTarget(self, action:#selector(buttonUp(sender:)), for: [.touchUpInside, .touchUpOutside]) } 
Interesting Posts