You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为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)

方法二:利用手势代理实现事件共存

如果需要更精细的控制触摸事件的传递逻辑,可以给手势设置代理,允许手势和视图的触摸事件同时处理。

  1. 让你的视图控制器遵循UIGestureRecognizerDelegate协议:
class YourMainViewController: UIViewController, UIGestureRecognizerDelegate {
    // 你的现有代码...
}
  1. 给手势设置代理并实现代理方法:
// 添加手势时设置代理
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里通过闭包回调处理点击事件,这样既能保留触摸动画,又能实现点击响应,完全避免事件冲突:

  1. 修改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)
    }
}
  1. 在主控制器中设置闭包:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 09:42:56