UIPanGestureRecognizer与collectionViewCell冲突:随机遮挡按钮问题
问题描述
我在CollectionViewCell上给container视图添加了UIPan手势识别器,代码如下:
let swipeToRight = UIPanGestureRecognizer(target: self, action: #selector(panHandler)) swipeToRight.minimumNumberOfTouches = 1 swipeToRight.maximumNumberOfTouches = 1 swipeToRight.delegate = self container.addGestureRecognizer(swipeToRight)
为避免手势干扰CollectionView滚动,我重写gestureRecognizerShouldBegin方法做兼容:
public override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { if let pan = gestureRecognizer as? UIPanGestureRecognizer { let velocity = pan.velocity(in: self) return abs(velocity.x) > abs(velocity.y) } return true }
原本运行正常,但后来随机出现问题:部分Cell顶部被一个带手势的UIView遮挡,导致Cell上的按钮无法点击。该视图的描述如下:
Printing description of $33: <UIView: 0x10b678d30; frame = (0 0; 410 357.667); gestureRecognizers = <NSArray: 0x280800660>; layer = <CALayer: 0x280484ce0>>
即使移除自定义的UIPan手势识别器,只保留gestureRecognizerShouldBegin方法,问题仍然随机出现。
解决方案
修复Cell复用的视图清理逻辑
CollectionViewCell复用过程中,未正确清理视图会导致额外UIView残留。在prepareForReuse方法中强制清理非预期的子视图和手势:override func prepareForReuse() { super.prepareForReuse() // 移除container上所有非自定义的子视图 container.subviews.forEach { subview in if !["你的自定义控件类名1", "你的自定义控件类名2"].contains(String(describing: type(of: subview))) { subview.removeFromSuperview() } } // 清理container上非自定义的手势 container.gestureRecognizers?.forEach { gesture in if gesture != swipeToRight { container.removeGestureRecognizer(gesture) } } }注意:需将
swipeToRight改为Cell类的实例变量,而非局部变量。限定
gestureRecognizerShouldBegin的处理范围
原方法会拦截所有手势识别器的判断,可能干扰系统原生手势逻辑。修改为仅处理自定义的pan手势:public override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { guard gestureRecognizer == swipeToRight else { // 其他手势交给系统默认逻辑处理 return super.gestureRecognizerShouldBegin(gestureRecognizer) } if let pan = gestureRecognizer as? UIPanGestureRecognizer { let velocity = pan.velocity(in: self) return abs(velocity.x) > abs(velocity.y) } return true }追踪神秘视图的添加时机
在Cell的layoutSubviews或didMoveToSuperview方法中打印子视图,定位视图出现的触发场景:override func layoutSubviews() { super.layoutSubviews() print("Container子视图列表:", container.subviews) }结合日志判断该视图是在Cell复用、手势触发还是其他操作后出现,进一步缩小问题范围。
内容的提问来源于stack exchange,提问作者martin wotterman
相关产品推荐
相关产品推荐

