Reputation: 10215
I want to implement UIView
subclass that will catch all touch events (especially touchesMoved) and pass them through. Is it possible?
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)
}
}
Upvotes: 0
Views: 1514
Reputation: 10215
I use this class:
class TouchlessView: UIView {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
let buttons = findViews(subclassOf: UIButton.self)
for button in buttons where button.frame.contains(point) {
return true
}
return false
}
}
Upvotes: 0
Reputation:
You can’t really do this. If your view receives touches it can’t pass it on to the view that would have received if your view isn’t there. To do this you’d basically have to reimplement the whole event routing. This would be really hard, or maybe even impossible without access to Apple internal API. But even if you got this right it could break with every iOS update.
But there is a different way to get all touch events while still having them delivered to the appropriate views. For this you create a subclass of UIApplication
and override the sendEvent(_:)
method. This is called for each event and dispatches it to the appropriate views. From there you can first do your special processing and then call super.sendEvent()
to send it to your windows as usual.
Of course there you don’t get different calls for touches began/moved/ended, but the information is there in your event object. First you need to check the event.type
property to see if you actually got a touch event. If so you can get all the touches from the event.allTouches
property. For each touch you can get the phase
which describes whether this touch began, moved, ended and so on.
Of course subclassing is not enough, you also have to tell the system to use your new subclass. To do this you annotate it as @objc(MyApplication)
where MyApplication
is the name of the class. This makes sure the Objective-C runtime can find the class by the name you gave it. Then you edit your Info.plist file and set this name for the "Principal class" key. (If you are not using the Xcode editor the key is also called NSPrincipalClass
).
Upvotes: 2