CustomAnimation
A type that defines how an animatable value changes over time.
Declaration
@preconcurrency protocol CustomAnimation : Hashable, SendableOverview
Use this protocol to create a type that changes an animatable value over time, which produces a custom visual transition of a view. For example, the follow code changes an animatable value using an elastic ease-in ease-out function:
struct ElasticEaseInEaseOutAnimation: CustomAnimation {
let duration: TimeInterval
func animate<V>(value: V, time: TimeInterval, context: inout AnimationContext<V>) -> V? where V : VectorArithmetic {
if time > duration { return nil } // The animation has finished.
let p = time / duration
let s = sin((20 * p - 11.125) * ((2 * Double.pi) / 4.5))
if p < 0.5 {
return value.scaled(by: -(pow(2, 20 * p - 10) * s) / 2)
} else {
return value.scaled(by: (pow(2, -20 * p + 10) * s) / 2 + 1)
}
}
}To create an Animation instance of a custom animation, use the init(_:) initializer, passing in an instance of a custom animation; for example:
Animation(ElasticEaseInEaseOutAnimation(duration: 5.0))To help make view code more readable, extend Animation and add a static property and function that returns an Animation instance of a custom animation. For example, the following code adds the static property elasticEaseInEaseOut that returns the elastic ease-in ease-out animation with a default duration of 0.35 seconds. Next, the code adds a method that returns the animation with a specified duration.
extension Animation {
static var elasticEaseInEaseOut: Animation { elasticEaseInEaseOut(duration: 0.35) }
static func elasticEaseInEaseOut(duration: TimeInterval) -> Animation {
Animation(ElasticEaseInEaseOutAnimation(duration: duration))
}
}To animate a view with the elastic ease-in ease-out animation, a view calls either .elasticEaseInEaseOut or .elasticEaseInEaseOut(duration:). For example, the follow code includes an Animate button that, when clicked, animates a circle as it moves from one edge of the view to the other, using the elastic ease-in ease-out animation with a duration of 5 seconds:
struct ElasticEaseInEaseOutView: View {
@State private var isActive = false
var body: some View {
VStack(alignment: isActive ? .trailing : .leading) {
Circle()
.frame(width: 100.0)
.foregroundColor(.accentColor)
Button("Animate") {
withAnimation(.elasticEaseInEaseOut(duration: 5.0)) {
isActive.toggle()
}
}
.frame(maxWidth: .infinity)
}
.padding()
}
}