AnimationState
struct · iOS 17.0+ · SDK 27.1
struct AnimationState<Value> where Value : VectorArithmeticA container that stores the state for a custom animation. An ``AnimationContext`` uses this type to store state for a ``CustomAnimation``. To retrieve the stored state of a context, you can use the ``AnimationContext/state`` property. However, a more convenient way to access the animation state is to define an ``AnimationStateKey`` and extend ``AnimationContext`` with a computed property that gets and sets the animation state, as shown in the following code: private struct PausableState<Value: VectorArithmetic>: AnimationStateKey { static var defaultValue: Self { .init() } } extension AnimationContext { fileprivate var pausableState: PausableState<Value> { get { state[PausableState<Value>.self] } set { state[PausableState<Value>.self] = newValue } } } When creating an ``AnimationStateKey``, it's convenient to define the state values that your custom animation needs. For example, the following code adds the properties `paused` and `pauseTime` to the `PausableState` animation state key: private struct PausableState<Value: VectorArithmetic>: AnimationStateKey { var paused = false var pauseTime: TimeInterval = 0.0 static var defaultValue: Self { .init() } } To access the pausable state in a `PausableAnimation`, the follow code calls `pausableState` instead of using the context's ``AnimationContext/state`` property. And because the animation state key `PausableState` defines properties for state values, the custom animation can read and write those values. struct PausableAnimation: CustomAnimation { let base: Animation func animate<V>(value: V, time: TimeInterval, context: inout AnimationContext<V>) -> V? where V : VectorArithmetic { let paused = context.environment.animationPaused let pausableState = context.pausableState var pauseTime = pausableState.pauseTime if pausableState.paused != paused { pauseTime = time - pauseTime context.pausableState = PausableState(paused: paused, pauseTime: pauseTime) } let effectiveTime = paused ? pauseTime : time - pauseTime let result = base.animate(value: value, time: effectiveTime, context: &context) return result } } ### Storing state for secondary animations A custom animation can also use `AnimationState` to store the state of a secondary animation. For example, the following code creates an ``AnimationStateKey`` that includes the property `secondaryState`, which a custom animation can use to store other state: private struct TargetState<Value: VectorArithmetic>: AnimationStateKey { var timeDelta = 0.0 var valueDelta = Value.zero var secondaryState: AnimationState<Value>? = .init() static var defaultValue: Self { .init() } } extension AnimationContext { fileprivate var targetState: TargetState<Value> { get { state[TargetState<Value>.self] } set { state[TargetState<Value>.self] = newValue } } } The custom animation `TargetAnimation` uses `TargetState` to store state data in `secondaryState` for another animation that runs as part of the target animation. struct TargetAnimation: CustomAnimation { var base: Animation var secondary: Animation func animate<V: VectorArithmetic>(value: V, time: Double, context: inout AnimationContext<V>) -> V? { var targetValue = value if let secondaryState = context.targetState.secondaryState { var secondaryContext = context secondaryContext.state = secondaryState let secondaryValue = value - context.targetState.valueDelta let result = secondary.animate( value: secondaryValue, time: time - context.targetState.timeDelta, context: &secondaryContext) if let result = result { context.targetState.secondaryState = secondaryContext.state targetValue = result + context.targetState.valueDelta } else { context.targetState.secondaryState = nil } } let result = base.animate(value: targetValue, time: time, context: &context) if let result = result { targetValue = result } else if context.targetState.secondaryState == nil { return nil } return targetValue } func shouldMerge<V: VectorArithmetic>(previous: Animation, value: V, time: Double, context: inout AnimationContext<V>) -> Bool { guard let previous = previous.base as? Self else { return false } var secondaryContext = context if let secondaryState = context.targetState.secondaryState { secondaryContext.state = secondaryState context.targetState.valueDelta = secondary.animate( value: value, time: time - context.targetState.timeDelta, context: &secondaryContext) ?? value } else { context.targetState.valueDelta = value } // Reset the target each time a merge occurs. context.targetState.secondaryState = .init() context.targetState.timeDelta = time return base.shouldMerge( previous: previous.base, value: value, time: time, context: &context) } }
Members (0)
This type has no directly callable members in this snapshot. See the framework’s skipped declarations for unsupported APIs.
Skipped declarations
1 declarations were excluded from these bindings. Each reason comes from the generator or the iOS SDK compiler.
AnimationState.subscript(_:)
Passing a Swift type itself is not supported.