我已经提到了关于按下按钮的无数其他问题,但与Swift没有太多关联。我使用touchUpInside事件将一个功能连接到一个按钮:
@IBAction func singleFire(sender: AnyObject){
//code
}
...和另一个功能,用于在按住相同按钮时重复调用上述功能,并在不再按下按钮时停止:
@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()
}
}
我不确定我做错了什么,我不知道如何将触摸事件设置到同一个按钮以获得不同的功能。
按住按钮时,您希望快速重复射击。
您的buttonDown
和buttonUp
方法需要在顶层定义,而不是在另一个函数内定义。出于演示目的,放弃从故事板中连接@IBAction
s并在viewDidLoad
中设置按钮更清楚:
class ViewController: UIViewController {
@IBOutlet weak var button: UIButton!
var timer: Timer?
var speedAmmo = 20
@objc func buttonDown(_ sender: UIButton) {
singleFire()
timer = Timer.scheduledTimer(timeInterval: 0.3, target: self, selector: #selector(rapidFire), userInfo: nil, repeats: true)
}
@objc func buttonUp(_ sender: UIButton) {
timer?.invalidate()
}
func singleFire() {
print("bang!")
}
@objc func rapidFire() {
if speedAmmo > 0 {
speedAmmo -= 1
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: #selector(buttonDown), for: .touchDown)
button.addTarget(self, action: #selector(buttonUp), for: [.touchUpInside, .touchUpOutside])
}
}
此外,我将.touchUpOutside
更改为[.touchUpInside, .touchUpOutside]
(以捕获两个补足事件)并在最初的singleFire
上调用buttonDown
进行单火。通过这些更改,按下按钮会立即触发,然后只要按住按钮,就会触发每个0.3
秒。
该按钮可以在故事板中连接,而不是在viewDidLoad
中设置。在这种情况下,将@IBAction
添加到buttonDown
和buttonUp
。然后按住Control键并单击故事板中的按钮,然后从Touch Down旁边的圆圈拖动到func buttonDown
,然后从Touch Up Inside和Touch Up Outside旁边的圆圈拖动到func buttonUp
。
在我的原始答案中,我回答了如何让按钮同时识别水龙头和长按的问题。在澄清的问题中,只要用户按下手指,您就会希望此按钮持续“触发”。如果是这种情况,则只需要一个手势识别器。
例如,在Interface Builder中,将长按手势识别器从对象库拖到按钮上,然后将“最小持续时间”设置为零:
然后你可以控制 - 从长按手势识别器拖动到助手编辑器中的代码并添加一个@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")
}
或者,如果您还想在用户将手指拖离按钮时停止触发,请添加对手势位置的检查:
@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
}
}
我的原始答案,回答了如何识别按钮上的水龙头和长按的不同问题,如下所示:
就个人而言,我会使用水龙头和长按手势识别器,例如:
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
上执行你的行动。它只取决于所需的用户体验。
仅供参考,您也可以在Interface Builder中添加这两个手势识别器(只需将对象库中的相应手势拖到按钮上,然后从手势识别器控制拖动到@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])
}