Control whether animations are animated or snap immediately to target values using AnimationMode
Animation modes determine whether Wave animates smoothly to a target value or snaps to it immediately. This is essential for interrupting animations and ensuring correct state updates.
// Start animating a circle from left to rightWave.animate(withSpring: spring, mode: .animated) { circle.animator.center = CGPoint(x: 500, y: 100)}// Later, you want the circle to snap to its final positioncircle.center = CGPoint(x: 500, y: 100)
Problem: Setting circle.center directly doesn’t work! The animator is still running and will override your value in the next frame.Solution: Use .nonAnimated mode to properly stop the animation:
When an animation is running, directly setting properties on the view (without using .animator) will be overridden by the animator on the next frame. Always use .nonAnimated mode to interrupt and snap.
When using SpringAnimator directly, you can control the mode via the mode property:
let animator = SpringAnimator<CGPoint>(spring: spring)animator.value = currentPositionanimator.target = targetPositionanimator.mode = .animated // or .nonAnimatedanimator.start()
You can even change the mode mid-animation:
animator.mode = .animatedanimator.start()// Later, decide to snap to target immediatelyanimator.mode = .nonAnimated// Animation will finish on the next frame
Changing mode to .nonAnimated is safer than calling stop(immediately: true) because it properly updates the animator state and fires completion handlers.
Wave.animate(withSpring: spring) { box.animator.center = targetPosition}// Later - this won't work!box.center = finalPosition // Will be overridden by animator
✅ Correct:
Wave.animate(withSpring: spring) { box.animator.center = targetPosition }// Later - use non-animated modeWave.animate(withSpring: spring, mode: .nonAnimated) { box.animator.center = finalPosition}
Both modes trigger completion handlers, but with different timing:
Wave.animate(withSpring: spring, mode: .animated) { view.animator.center = target} completion: { finished, retargeted in // Called after spring settles (could be 1+ seconds) print("Animated completion")}Wave.animate(withSpring: spring, mode: .nonAnimated) { view.animator.center = target} completion: { finished, retargeted in // Called immediately on next frame (1/60th of a second) print("Non-animated completion")}