如何解决Swift/SpriteKit中按钮TouchesEnded处理失效的问题?
SpriteKit按钮快速滑动点击后无法恢复原色
我用Swift/SpriteKit开发了一款iOS小型应用,其中包含一个按下时会变成绿色的黑色按钮。按钮正常点击时功能没问题,但如果快速半滑动半点击按钮,手指离开屏幕后按钮会一直保持绿色,无法恢复成黑色。
以下是我的代码:
// // GameScene.swift // box button only test 2025 // // Created by Chris Tucker on 3/30/25. // import SpriteKit import GameplayKit class GameScene: SKScene { let rightBox = SKSpriteNode(color: SKColor.black, size: CGSize(width: 100, height: 100)) override func didMove(to view: SKView) { rightBox.position = CGPoint(x: 0, y: 0) rightBox.name = "rightBoxName" addChild(rightBox) } func touchDown(atPoint pos : CGPoint) { if rightBox.contains(pos) { rightBox.color = .green } } func touchMoved(toPoint pos : CGPoint) { if rightBox.contains(pos) { rightBox.color = .green } else { rightBox.color = .black } } func touchUp(atPoint pos : CGPoint) { if rightBox.contains(pos) { rightBox.color = .black // set } } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { for t in touches { self.touchDown(atPoint: t.location(in: self)) } } override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { for t in touches { self.touchMoved(toPoint: t.location(in: self)) } } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { for t in touches { self.touchUp(atPoint: t.location(in: self)) } } override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { for t in touches { self.touchUp(atPoint: t.location(in: self)) } } override func update(_ currentTime: TimeInterval) { // Called before each frame is rendered } }
问题原因
当前代码仅在手指抬起位置处于按钮内部时,才会将按钮恢复为黑色。但快速滑动场景下,touchesMoved可能未及时触发,或手指抬起时已移出按钮范围,导致按钮停留在绿色状态。且代码未跟踪按钮的按下状态,完全依赖触摸位置判断颜色,逻辑存在漏洞。
修复方案
添加布尔变量跟踪按钮的按下状态,触摸结束时无论手指位置如何,只要按钮曾被按下,就恢复原色。
修改后的代码:
import SpriteKit import GameplayKit class GameScene: SKScene { let rightBox = SKSpriteNode(color: SKColor.black, size: CGSize(width: 100, height: 100)) // 新增变量跟踪按钮按下状态 private var isRightBoxPressed = false override func didMove(to view: SKView) { rightBox.position = CGPoint(x: 0, y: 0) rightBox.name = "rightBoxName" addChild(rightBox) } func touchDown(atPoint pos : CGPoint) { if rightBox.contains(pos) { rightBox.color = .green isRightBoxPressed = true } } func touchMoved(toPoint pos : CGPoint) { if rightBox.contains(pos) { rightBox.color = .green isRightBoxPressed = true } else { rightBox.color = .black isRightBoxPressed = false } } func touchUp(atPoint pos : CGPoint) { // 无需判断手指位置,只要按钮曾被按下就恢复原色 if isRightBoxPressed { rightBox.color = .black isRightBoxPressed = false } } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { for t in touches { self.touchDown(atPoint: t.location(in: self)) } } override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { for t in touches { self.touchMoved(toPoint: t.location(in: self)) } } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { for t in touches { self.touchUp(atPoint: t.location(in: self)) } } override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { for t in touches { self.touchUp(atPoint: t.location(in: self)) } } override func update(_ currentTime: TimeInterval) { // Called before each frame is rendered } }
关键修改点
- 新增
isRightBoxPressed变量,专门跟踪按钮的按下状态 touchDown时标记按钮为按下状态touchMoved时根据触摸位置更新状态与颜色touchUp时直接依据之前的按下状态恢复颜色并重置状态
此修改后,无论手指是快速滑动离开还是正常抬起,按钮都会正确恢复原色。
内容的提问来源于stack exchange,提问作者Chris Tucker
相关产品推荐
相关产品推荐

