Feature parity SwiftUI's Spring (same properties & methods)
smooth, bouncy & snappy spring presets: Spring.snappy, Spring.snappy(duration: CGFloat = 0.5, extraBounce: CGFloat = 0.0), etc.
Spring(duration: CGFloat, bounce: CGFloat)
Init via a SwiftUI spring: Spring(_ spring: SwiftUI.Spring)
Init via a specified settling time, damping ratio and epsilon (the threshold for how small all subsequent values need to be before the spring is considered to have settled): Spring(settlingDuration: TimeInterval, dampingRatio: Double, epsilon: Double = 0.001)
SpringAnimator
Now uses AnimatableData instead of SpringInterpolatable.
Double, Float, CGFloat, CGPoint, CGSize, CGRect, CATransform3D, WaveColor, CGColor, CGAffineTransform support AnimatableData by default.
/// A protocol that describes an animatable value type.
public protocol AnimatableData: Equatable, Comparable {
/// The type defining the data to animate.
associatedtype AnimatableData: VectorArithmetic = Self
/// The data to animate.
var animatableData: AnimatableData { get }
/// Initializes with animatable data.
init(_ animatableData: AnimatableData)
/// Scaled integral representation of the value.
var scaledIntegral: Self { get }
static var zero: Self { get }
}
Double, Float, CGFloat and Arrays containing these confirm to VectorArithmetic (typealias: AnimatableVector) and can be used as animatable data. Apple also uses VectorArithmetic for its SwiftUI Animatable protocol to animate. It allows very quick calculations. I use vDSP which calculates many values parallel in one cpu cycle.
public struct SomeStruct {
let value1: CGFloat
let value2: CGFloat
}
extension SomeStruct: AnimatableData {
public var animatableData: AnimatableVector {
[value1, value2]
}
public init(_ animatableData: AnimatableVector) {
self.value1 = animatableData[0]
self.value1 = animatableData[1]
}
public static var zero: Self = SomeStruct(value1: 0, value2: 0)
}
AnimatablePropertyProvider protocol
Extending a class with AnimatablePropertyProvider automatically adds animator: PropertyAnimator<Class>.
public protocol AnimatablePropertyProvider: AnyObject {
/// Use this property to set any animatable properties in an ``Wave/animate(withSpring:delay:gestureVelocity:animations:completion:)`` animation block.
var animator: PropertyAnimator<Self> { get }
}
To set/get a property animated use the keyPath of a property to animate (that conforms to AnimatableData) on the animator.
extension NSView: AnimatablePropertyProvider { }
Wave.animate(withSpring: .bouncy) {
myView.animator[\.frame] = newFrame // sets a new frame animated.
let currentFrame = myView.animator[\.frame] // current frame (either the target of the spring animation or the frame)
}
This allows modularity. E.g.
extension NSView: AnimatablePropertyProvider { }
extension PropertyAnimator<NSView> {
var frame: CGRect {
get { self[\.frame] }
set { self[\.frame] = newValue }
}
}
extension CALayer: AnimatablePropertyProvider { }
extension PropertyAnimator<CALayer> {
var opacity: CGFloat {
get { self[\.opacity] }
set { self[\.opacity] = newValue }
}
}
Wave.animate(withSpring: .bouncy) {
myView.animator.frame = newFrame
myLayer.animator.opacity = 0.5
}
The current animation velocity can always be accessed via animators animationVelocity and the keyPath of the animated property.
let currentVelocity = myView.animator.animationVelocity[\.frame]
Spring + CAKeyframeAnimation
Generate a CAKeyframeAnimation from a Spring.
let animation = Spring.bouncy.keyframeAnimation()
animation.keyPath = "frame"
layer.add(animation, forKey: "MyAnimation")
Wave
Removed AnimationMode. Instead useSpring.nonAnimated or Wave.nonAnimate(changes: () -> Void). This allows for easier integration of future animation types like (Easing) which I plan to add.
Extended animation support
Spring
Spring.snappy
,Spring.snappy(duration: CGFloat = 0.5, extraBounce: CGFloat = 0.0)
, etc.Spring(duration: CGFloat, bounce: CGFloat)
Spring(_ spring: SwiftUI.Spring)
Spring(settlingDuration: TimeInterval, dampingRatio: Double, epsilon: Double = 0.001)
SpringAnimator
AnimatableData
instead ofSpringInterpolatable
.Double
,Float
,CGFloat
,CGPoint
,CGSize
,CGRect
,CATransform3D
,WaveColor
,CGColor
,CGAffineTransform
support AnimatableData by default.Double, Float, CGFloat and Arrays containing these confirm to
VectorArithmetic
(typealias:AnimatableVector
) and can be used as animatable data. Apple also usesVectorArithmetic
for its SwiftUIAnimatable
protocol to animate. It allows very quick calculations. I use vDSP which calculates many values parallel in one cpu cycle.AnimatablePropertyProvider protocol
Extending a class with
AnimatablePropertyProvider
automatically addsanimator: PropertyAnimator<Class>
.To set/get a property animated use the keyPath of a property to animate (that conforms to
AnimatableData
) on the animator.This allows modularity. E.g.
The current animation velocity can always be accessed via animators
animationVelocity
and the keyPath of the animated property.Spring + CAKeyframeAnimation
Generate a
CAKeyframeAnimation
from a Spring.Wave
AnimationMode
. Instead useSpring.nonAnimated
orWave.nonAnimate(changes: () -> Void)
. This allows for easier integration of future animation types like (Easing) which I plan to add.