---
title: CustomAnimation
framework: swiftui
role: symbol
role_heading: Protocol
path: swiftui/customanimation
---

# CustomAnimation

A type that defines how an animatable value changes over time.

## Declaration

```swift
@preconcurrency protocol CustomAnimation : Hashable, Sendable
```

## Overview

Overview 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)         }     } } note: To maintain state during the life span of a custom animation, use the state property available on the context parameter value. You can also use context’s environment property to retrieve environment values from the view that created the custom animation. For more information, see AnimationContext. 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()     } }

## Topics

### Animating a value

- [animate(value:time:context:)](swiftui/customanimation/animate(value:time:context:).md)

### Getting the velocity

- [velocity(value:time:context:)](swiftui/customanimation/velocity(value:time:context:).md)

### Determining whether to merge

- [shouldMerge(previous:value:time:context:)](swiftui/customanimation/shouldmerge(previous:value:time:context:).md)

## Relationships

### Inherits From

- [Equatable](swift/equatable.md)
- [Hashable](swift/hashable.md)
- [Sendable](swift/sendable.md)
- [SendableMetatype](swift/sendablemetatype.md)

## See Also

### Creating custom animations

- [AnimationContext](swiftui/animationcontext.md)
- [AnimationState](swiftui/animationstate.md)
- [AnimationStateKey](swiftui/animationstatekey.md)
- [UnitCurve](swiftui/unitcurve.md)
- [Spring](swiftui/spring.md)
