我想实现 UIView
子类,它将捕获所有触摸事件(尤其是 touchesMoved)并传递它们。可能吗?
class PassthroughView: UIView {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let view = super.hitTest(point, with: event)
return view == self ? nil : view
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touchesBegan")
super.touchesBegan(touches, with: event)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touchesMoved") //not called
super.touchesMoved(touches, with: event)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touchesEnded")
super.touchesEnded(touches, with: event)
}
}
最佳答案
你真的不能这样做。如果您的 View 接收到触摸,它无法将其传递给如果您的 View 不存在时本应接收到的 View 。为此,您基本上必须重新实现整个事件路由。如果不访问 Apple 内部 API,这将非常困难,甚至可能是不可能的。但即使你做对了,它也可能会随着每次 iOS 更新而中断。
但是有一种不同的方法可以获取所有触摸事件,同时仍然将它们传送到适当的 View 。为此,您创建了 UIApplication
的子类并覆盖了 sendEvent(_:)
方法。这是为每个事件调用并将其分派(dispatch)到适当的 View 。从那里您可以首先进行特殊处理,然后像往常一样调用 super.sendEvent()
将其发送到您的窗口。
当然,您不会收到触摸开始/移动/结束的不同调用,但信息存在于您的事件对象中。首先,您需要检查 event.type
属性以查看您是否确实获得了触摸事件。如果是这样,您可以从 event.allTouches
属性中获取所有触摸。对于每次触摸,您可以获得 phase
,它描述了此触摸是否开始、移动、结束等。
当然子类化是不够的,你还必须告诉系统使用你的新子类。为此,您将其注释为 @objc(MyApplication)
,其中 MyApplication
是类的名称。这确保 Objective-C 运行时可以通过您给它的名称找到该类。然后编辑 Info.plist 文件并为“Principal class”键设置这个名称。 (如果您不使用 Xcode 编辑器,该 key 也称为 NSPrincipalClass
)。
关于swift - UIView 捕捉触摸事件并传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49615930/