Swift 4中touchesBegan监听未被调用的原因排查
解决你的UIControl子类touchesBegan不触发问题
Hey there, let's break down why your touchesBegan method isn't getting called when you tap your custom button:
核心原因
你的Btn类是UIControl的子类,但你在它内部嵌套了一个UIButton——而UIButton本身也是UIControl的子类,它会优先拦截触摸事件。当你点击按钮区域时,触摸事件会被内部的UIButton直接捕获并处理,根本不会传递到外层的Btn类,所以你重写的touchesBegan自然不会执行。
另外还有个小问题:你创建Btn实例时没有设置它的frame,默认是CGRect.zero,这会导致父类控件的可交互区域为0,即使内部按钮有尺寸,也会影响触摸事件的响应逻辑。
解决方案
根据你的需求,有两种处理方式:
方式一:移除内部的UIButton,直接自定义UIControl外观
如果你的需求只是创建一个自定义样式的可交互控件,完全不需要嵌套UIButton,直接给Btn类设置外观即可:
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 给Btn设置明确的frame(或者用AutoLayout约束) let button = Btn(frame: CGRect(x: 100, y: 100, width: 50, height: 50)) view.addSubview(button) } } class Btn: UIControl { override init(frame: CGRect) { super.init(frame: frame) backgroundColor = .green // 直接设置自身背景色 } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) backgroundColor = .green } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) print("test") // 现在点击会正常打印了 } }
方式二:保留内部UIButton,调整事件响应逻辑
如果你确实需要保留内部的UIButton(比如复用它的某些内置功能),可以通过以下两种方式让外层Btn类接收到触摸事件:
方法1:禁用内部按钮的用户交互
让内部按钮不拦截触摸事件,把事件交给父类处理:
class Btn: UIControl { fileprivate let button: UIButton = { let swapButton = UIButton() let size = CGFloat(50) swapButton.frame.size = CGSize(width: size, height: size) swapButton.backgroundColor = UIColor.green swapButton.isUserInteractionEnabled = false // 禁用内部按钮的交互能力 return swapButton }() // 其余代码不变... }
方法2:转发内部按钮的事件到父类
如果需要内部按钮保留部分交互功能,可以给它添加事件监听,然后在回调里执行父类的逻辑:
class Btn: UIControl { fileprivate let button: UIButton = { let swapButton = UIButton(type: .custom) let size = CGFloat(50) swapButton.frame.size = CGSize(width: size, height: size) swapButton.backgroundColor = UIColor.green return swapButton }() override init(frame: CGRect) { super.init(frame: frame) addSubview(button) // 给内部按钮添加点击事件监听 button.addTarget(self, action: #selector(internalButtonTapped), for: .touchUpInside) } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) addSubview(button) button.addTarget(self, action: #selector(internalButtonTapped), for: .touchUpInside) } @objc private func internalButtonTapped() { print("Internal button tapped") // 这里可以手动触发父类的触摸逻辑,或者直接执行你需要的代码 print("test") // 直接调用你的业务逻辑即可 } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) print("test") } }
别忘了,创建Btn实例时一定要给它设置有效的frame或者添加AutoLayout约束,否则控件的可交互区域为0,也会导致触摸事件无法被捕获哦!
内容的提问来源于stack exchange,提问作者slava_slava
相关产品推荐
相关产品推荐

