VoiceOver开启时如何忽略Tap手势?CollectionView手势冲突问题
问题分析:VoiceOver下CollectionView单元格手势与选中代理的冲突
视图层级示例
CollectionView Cell ㄴ A ㄴㄴ B
这是我的CollectionView单元格视图层级示例。
问题情况
我在B视图中添加了Tap手势及对应操作。开启无障碍功能VoiceOver后,预期会调用CollectionView的didSelectItemAt代理方法,但实际触发的是Tap手势操作。我从未配置过任何与无障碍相关的手势,且该现象仅在特定视图中复现。
核心疑问
VoiceOver与Tap手势是否存在关联?导致此问题的原因是什么?
相关代码
private lazy var AContainer = UIView().then { $0.addGestureRecognizer(UITapGestureRecognizer.init(target: self, action: #selector(actionGesture))) } AContainer.flex.define { flex in flex.addItem(textLabel) flex.addItem(testImageView) .size(10) } contentView.flex.addItem().define { flex in flex.addItem(AContainer) } @objc func actionGesture() { print("testestest") }
原因解析
VoiceOver点击逻辑与手势优先级
VoiceOver开启后,用户的“点击”操作实际是单指双击,系统会将其转化为触摸事件传递给视图。而手势识别器的响应优先级默认高于CollectionView的单元格选中逻辑——当触摸事件落在添加了手势的子视图(B视图)上时,手势会优先拦截并处理事件,导致CollectionView的didSelectItemAt代理无法触发。特定视图复现的可能原因
该现象仅在特定视图出现,大概率是其他视图的手势做了特殊配置:
- 其他视图的手势设置了
cancelsTouchesInView = false,允许事件在手势识别后继续传递给CollectionView; - 其他视图的手势通过
UIGestureRecognizerDelegate的shouldReceiveTouch方法,在VoiceOver开启时跳过了手势处理; - 其他视图的子视图
isUserInteractionEnabled为false,手势无法触发,事件自然传递到CollectionView的选中逻辑。
解决方向
如果希望优先触发CollectionView的didSelectItemAt,可以尝试以下方案:
- 给Tap手势设置
cancelsTouchesInView = false,让事件在手势识别后继续向下传递; - 通过
UIAccessibility.isVoiceOverRunning判断无障碍状态,在手势触发前跳过操作,转而手动调用CollectionView的选中逻辑; - 设置手势的
delaysTouchesBegan = true,让CollectionView有机会先响应选中事件。
内容的提问来源于stack exchange,提问作者ga-yo
相关产品推荐
相关产品推荐

