如何实现可捕捉触摸事件(含touchesMoved)并透传的UIView子类?
实现可捕捉触摸事件并透传的UIView子类
当然可行!你已经找对了核心方向,通过重写hitTest(_:with:)方法能实现事件透传,同时重写触摸事件方法就能完整捕捉所有触摸动作。我来帮你补全代码并拆解关键逻辑:
完整实现代码
class PassthroughView: UIView { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { // 先让系统找到原本应该响应事件的目标视图 let targetView = super.hitTest(point, with: event) // 如果目标视图是当前view本身,返回nil让事件继续向下传递给底层视图 // 如果目标是子视图,直接返回它,保证子视图能正常响应事件 return targetView == self ? nil : targetView } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) print("📌 捕捉到 touchesBegan 事件") // 这里可以添加自定义的触摸开始处理逻辑 } override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesMoved(touches, with: event) print("📌 捕捉到 touchesMoved 事件") // 示例:获取当前触摸位置 if let touch = touches.first { let location = touch.location(in: self) print("当前触摸坐标: \(location)") } } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesEnded(touches, with: event) print("📌 捕捉到 touchesEnded 事件") } override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesCancelled(touches, with: event) print("📌 捕捉到 touchesCancelled 事件") } }
关键逻辑说明
事件透传的核心:
hitTest(_:with:)- 这个方法的作用是定位当前触摸点对应的最终响应视图。
- 当判断
targetView == self时返回nil,表示当前view放弃成为事件响应者,系统会自动在当前view的底层视图中继续寻找合适的响应对象,从而实现事件透传。 - 如果触摸点落在当前view的子视图上,
super.hitTest会递归找到那个子视图,我们直接返回它,确保子视图能正常处理事件。
触摸事件的捕捉
- 重写
touchesBegan、touchesMoved等方法后,事件会先经过当前view的处理逻辑,再传递给后续的响应者(底层视图或子视图)。 - 必须调用
super的对应方法,否则事件传递链会被中断,底层视图将无法收到触摸事件。
- 重写
使用注意事项
- 确保当前
PassthroughView的isUserInteractionEnabled属性为true(默认值就是true,除非你手动修改过)。 - 即使view有多层子视图嵌套,这个逻辑依然有效,因为
super.hitTest会自动递归找到最底层的响应视图。
内容的提问来源于stack exchange,提问作者ChikabuZ
相关产品推荐
相关产品推荐

