As everybody knows, when using a mouse on a computer a drag operation occurs when the mouse button is pressed, then the device is moved, and eventually the button is released. It’s a continuous and precise operation.

In iOS we have (less precise) touches instead, but sometimes we do want to react to a drag operation similarly, upon beginning, moving, and eventually ending touches.

UIPanGestureRecognizer does a pretty good job to identify such drag operations itself, except that when it reaches its began state, the user has already moved the touch(es) a bit and we don’t know the initial location anymore – there’s no locationInViewWhenTouchesBegan property – while we’d need it to accurately compute coordinate deltas for responding to the drag operation.

(In a way that is expected, because we don’t want the pan operation to begin immediately when the first touch begins – as we are waiting to see if the user wants to actually pan or do something else.)

Update: While this is annoying, it is the way NSPanGestureRecognizer works with mouse events in macOS Cocoa development too, just that it is very difficult to see the behavior there; to catch the issue, you’d need to start dragging with the mouse from a limit of the draggable area of an element, towards the space outside that element.

To solve this problem (at least today) we need to specialize the recognizer class ourselves, reading and preserving the location in view when the touches actually begin, and use the specialization instead. Note below how we define an initial-location-in-view property for this purpose. (You would need to make the class and property public if you would want to use them outside a framework, though.)

And/or if you need the similar implementation for macOS development (instead), i.e. inheriting from NSPanGestureRecognizer, here we go again (but note that the client code is exactly the same as above, so I won’t repeat that part below):