为UIStackView中的自定义UIView添加点击手势后,touchesEnded方法无法触发的解决方案
UIStackView中的自定义UIView添加点击手势后,touchesEnded方法无法触发的解决方案
嘿,我帮你分析下这个问题哈~ 你遇到的情况是因为UITapGestureRecognizer默认会拦截触摸事件:当它成功识别出点击手势后,就会取消后续的触摸事件传递,导致你的自定义SLView里的touchesEnded方法得不到调用。下面给你几种可行的解决办法:
方法一:禁用手势的cancelsTouchesInView属性
这个属性默认是true,改成false之后,手势识别完成后不会中断视图本身的触摸事件流程,这样你的缩放动画和点击回调都能正常工作。
修改你添加手势的代码,给每个手势加上这行设置:
let contactGesture = UITapGestureRecognizer(target: self, action: #selector(self.contactWithDeveloper)) contactGesture.cancelsTouchesInView = false // 关键代码 self.settingsMenu.subviews[0].addGestureRecognizer(contactGesture) let restoreGesture = UITapGestureRecognizer(target: self, action: #selector(self.restorePurchase)) restoreGesture.cancelsTouchesInView = false // 关键代码 self.settingsMenu.subviews[1].addGestureRecognizer(restoreGesture)
方法二:利用手势代理实现事件共存
如果需要更精细的控制触摸事件的传递逻辑,可以给手势设置代理,允许手势和视图的触摸事件同时处理。
- 让你的视图控制器遵循
UIGestureRecognizerDelegate协议:
class YourMainViewController: UIViewController, UIGestureRecognizerDelegate { // 你的现有代码... }
- 给手势设置代理并实现代理方法:
// 添加手势时设置代理 let contactGesture = UITapGestureRecognizer(target: self, action: #selector(self.contactWithDeveloper)) contactGesture.delegate = self self.settingsMenu.subviews[0].addGestureRecognizer(contactGesture) let restoreGesture = UITapGestureRecognizer(target: self, action: #selector(self.restorePurchase)) restoreGesture.delegate = self self.settingsMenu.subviews[1].addGestureRecognizer(restoreGesture) // 实现代理方法,允许手势和视图触摸事件同时处理 func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true }
方法三:把点击逻辑整合到自定义View中(更简洁的方案)
其实你可以不用额外添加手势,直接在SLView里通过闭包回调处理点击事件,这样既能保留触摸动画,又能实现点击响应,完全避免事件冲突:
- 修改
SLView类,添加点击回调闭包:
class SLView: UIView { // 添加点击回调闭包 var onTap: (() -> Void)? override init(frame: CGRect) { super.init(frame: frame) } required init(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { animateScale(to: 0.9, duration: 0.4) } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { animateScale(to: 1, duration: 0.38) // 触发点击回调 onTap?() } private func animateScale(to scale: CGFloat, duration: TimeInterval) { UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 1.0, options: [], animations: { self.transform = CGAffineTransform(scaleX: scale, y: scale) }, completion: nil) } }
- 在主控制器中设置闭包:
func contextMenu() { for index in 1...2 { itemView = SLView() itemView.tag = index // ... 你的其他视图设置代码 // 根据tag绑定对应的点击逻辑 itemView.onTap = { [weak self] in guard let self = self else { return } if index == 1 { self.contactWithDeveloper() } else { self.restorePurchase() } } settingsMenu.addArrangedSubview(itemView) // ... 约束设置代码 } // 这里可以删掉原来添加手势的代码了 }
备注:内容来源于stack exchange,提问作者Alex Smith
相关产品推荐
相关产品推荐

