When using UIPanGestureRecognizer and detecting UIGestureRecognizerStateEnded, then the velocity of the gesture is not the true velocity. Instead, it\'
This is the only way to really know the velocity when the finger comes up:
have some variables...
var cat: CADisplayLink? = nil
var prevTime = CFAbsoluteTimeGetCurrent()
var lastKnownPosition: CGFloat = 0
var lastKnownActualVelocity: Double = 0
and then ...
@objc func _checkVelocityEveryTrueFrame() {
let newTime = CFAbsoluteTimeGetCurrent()
let frameTime = newTime - prevTime
prevTime = newTime
let newPos = yourConstraint.constant
lastKnownActualVelocity = Double(newPos - lastKnownPosition) / frameTime
lastKnownPosition = newPos
print("- \(frameTime) \(lastKnownPosition) \(lastKnownActualVelocity)")
}
@objc func dragOrFlick(_ p: UIPanGestureRecognizer) {
if p.state == .began {
cat?.invalidate()
cat = nil
cat = CADisplayLink(target: self,
selector: #selector(_checkVelocityEveryTrueFrame))
cat?.add(to: .main, forMode: .common)
}
if p.state == .changed {
... p.translation(in: ...
yourConstraint.constant = new position...
}
if p.state == .ended {
cat?.invalidate()
cat = nil
let trueFinalVelocity = lastKnownActualVelocity
print("trueFinalVelocity is truly \(trueFinalVelocity)")
}
}
That's it. As far as I know there's no simpler way.
+ Footnote. As any game programmer will tell you, even this is a bit shoddy; it gives the platonic velocity over one frame: purists would smooth it a little over a discussable amount of frames :/ It's a tricky issue.