代码生成的FrameView开启用户交互后拦截UIButton点击事件如何解决?
问题背景
- 应用界面包含多类核心视图:从Nib实例化的列表视图面板、FrameView(UIView子类)、FrameView动态生成的浅灰色绘图子视图(带删除红点按钮)、通过Storyboard添加的左下角核心导航按钮
- 绘图内容属于Drawing Object,与列表选中项为多对多关系,选中列表项时对应绘图面板会被添加为FrameView的子视图,同时开启FrameView的用户交互以保证删除按钮可点击
- 导航按钮已设置较高zPosition,但FrameView开启用户交互后,导航按钮无法接收任何点击和手势事件
问题原因
zPosition仅控制视图的渲染显示层级,不会影响事件响应链的传递顺序。 iOS系统的事件传递规则为:从window层级开始向下遍历,优先检查后添加的视图、父视图层级更靠前的视图,只要视图开启用户交互且点击区域匹配,就会优先拦截事件,与zPosition的配置无关。这就是调整导航按钮zPosition无法解决问题的核心原因。
解决方案
重写FrameView子类的hitTest方法即可完美解决问题,代码实现如下:
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let view = super.hitTest(point, with: event) return view == self ? nil : view }
该实现的逻辑为:当点击事件命中的目标是FrameView本身时,直接返回nil,让事件继续向下传递给下方的导航按钮;如果命中的是FrameView的子视图(比如绘图面板的删除按钮),则正常返回对应的子视图处理事件。既保证了FrameView上的所有子视图交互正常,也不会拦截下方其他视图的事件,对原有业务逻辑的侵入性极低。
补充说明
- 该实现适配最新Swift版本与iOS系统事件响应机制
- 无需调整现有视图的层级结构、添加顺序或zPosition配置即可生效
内容的提问来源于stack exchange,提问作者Dan Donaldson
相关产品推荐
相关产品推荐

