I requested the query on Apple’s developer boards and that is the reply from “Apple Frameworks Engineer”:
There is a false impression right here that’s inflicting you issues. I might suggest this video from WWDC20 beginning right here (however actually simply the entire video):
https://developer.apple.com/movies/play/wwdc2020/10094/?time=146
A pointer-based contact is barely going to be
UITouch.Part.started
->UITouch.Part.ended
when you will have clicked down on the pointing machine (there may also be an relatedbuttonMask
). When your finger is on the contact floor of the trackpad or Magic Mouse it should not be in these phases, however a part likeUITouch.Part.regionEntered
orUITouch.Part.regionMoved
.Gestures like
UIPanGestureRecognizer
,UITapGestureRecognizer
, andUILongPressGestureRecognizer
don’t devour touches in these phases, in order that’s why they aren’t working for you. And to be clear, there is no such thing as a option to inform these gestures to take action.The one gesture that consumes these sort of hovering touches is
UIHoverGestureRecognizer
. I might suggest including aUIHoverGestureRecognizer
to one among your views. Do notice that that is going to fireplace every time the pointer is seen and inside your view, so if it is a giant container, that could possibly be frequent. You could wish to allow this gesture when the momentum spinning begins, however in any other case preserve it disabled.Hope that helps!
This did remedy my downside, however it turned out that I could not simply activate the hover recognizer instantly after my pan recognizer ended — it might fireplace off some residual .modified occasions and trigger the coasting animation to freeze instantly.
So my implementation was to start out looking ahead to the touches when my pan recognizer ended, however after a brief delay of 1/tenth of a second. I wrote this scheduleStartWatchingForTrackpadTouches() technique for my view controller and had the .ended handler for the pan recognizer name it:
func scheduleStartWatchingForTrackpadTouches() {
DispatchQueue.most important.asyncAfter(deadline: .now() + 0.1) { [weak self] in
self?.startWatchingForTrackpadTouches()
}
}
Then I used this pair of strategies to create and activate/deactivate the recognizer as wanted:
func startWatchingForTrackpadTouches() {
// Create the recognizer the primary time by means of
if hoverRecognizer == nil {
hoverRecognizer = UIHoverGestureRecognizer(goal: self, motion: #selector(handleHover(_:)))
}
// Add the recognizer to the view
if let recognizer = hoverRecognizer {
view.addGestureRecognizer(recognizer)
}
}
func stopWatchingForTrackpadTouches() {
// Take away the recognizer from the view
if let recognizer = hoverRecognizer {
view.removeGestureRecognizer(recognizer)
}
}
Lastly, that is the occasion handler for the recognizer:
@objc non-public func handleHover(_ recognizer: UIHoverGestureRecognizer) {
if recognizer.state == .modified {
// Notify of contact start
touchesBegan()
// Don’t watch till explicitly requested
stopWatchingForTrackpadTouches()
}
}
On the primary .modified message I name a technique named touchesBegan() for my part controller to freeze the animations, after which I take away the recognizer so it solely fires as soon as and is disabled till it is wanted for the subsequent pan gesture.