Swift中移动的自定义UIImageView触摸无响应问题求解
解决GameViewController中touchesBegan无法响应自定义GameTile的问题
我明白你现在卡在哪了——你做了个瓷砖下落游戏,自定义了继承自UIImageView的GameTile类,也给瓷砖开了用户交互,但GameViewController里的touchesBegan方法就是没法捕捉到触摸瓷砖的事件。下面给你分析几个可能的原因,还有对应的解决办法:
先补全你的GameTile初始化代码的小问题
首先看你贴的GameTile代码,required init?(coder aDecoder: NSCoder)里的fatalErro...没写完,这会导致编译错误,先把它补全:
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
方案1:让GameTile自己处理触摸(更推荐的做法)
其实iOS开发里,视图的触摸事件交给视图自己处理会更符合MVC逻辑,也更简单。你可以直接在GameTile类里重写touchesBegan方法,这样瓷砖被触摸时自己就能触发隐藏操作:
class GameTile: UIImageView { init(named: String, frame: CGRect) { super.init(frame: frame) self.image = UIImage(named: named) self.isUserInteractionEnabled = true } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } // 重写触摸开始的方法 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) // 触摸时隐藏瓷砖 self.isHidden = true // 如果需要把触摸事件通知给ViewController,可以用闭包或者代理 // 比如定义一个闭包: // var onTap: (() -> Void)? // 然后在这里调用:onTap?() } }
这样修改后,只要瓷砖被触摸,就会自己隐藏,根本不需要依赖ViewController的touchesBegan。如果需要把触摸事件同步给ViewController做其他逻辑(比如计分),可以给GameTile加个闭包或者代理,这个后续有需要再扩展就行。
方案2:让GameViewController的touchesBegan捕获触摸
如果你一定要在ViewController里统一处理所有瓷砖的触摸,那需要注意几个点:
- 确保ViewController的view(也就是瓷砖的父视图)的
isUserInteractionEnabled是true(默认是true,但如果不小心改了要改回来) - 没有其他视图覆盖在瓷砖上面,挡住了触摸事件
- 在ViewController的touchesBegan里,要判断触摸点是否落在某个GameTile上:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) guard let touch = touches.first else { return } // 获取触摸点在ViewController视图中的位置 let touchLocation = touch.location(in: self.view) // 遍历所有子视图,找到被触摸的GameTile for subview in self.view.subviews { if let tile = subview as? GameTile { // 注意:如果用AutoLayout布局瓷砖,frame可能不准确,用point(inside:)更可靠 let localTouchPoint = self.view.convert(touchLocation, to: tile) if tile.point(inside: localTouchPoint, with: event) { tile.isHidden = true break } } } }
这里用point(inside:)而不是直接判断frame.contains(touchLocation),是因为如果你的瓷砖用AutoLayout布局,frame的数值可能不是实时更新的,转换到瓷砖本地坐标系再判断会更准确。
最后再检查两个小细节
- 确保你创建GameTile实例后,确实把它添加到了ViewController的view上:
let tile = GameTile(named: "你的瓷砖图片名", frame: CGRect(x: 100, y: 0, width: 50, height: 50)) self.view.addSubview(tile) - 检查你的瓷砖图片是否存在,如果图片找不到,GameTile会是透明的,但触摸还是应该响应,不过最好确认图片资源没问题。
内容的提问来源于stack exchange,提问作者K.K.D
相关产品推荐
相关产品推荐

