You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

132 lines
3.9 KiB

//
// AnyValueProvider.swift
// lottie-swift
//
// Created by Brandon Withrow on 1/30/19.
//
import CoreGraphics
import Foundation
// MARK: - AnyValueProvider
/// `AnyValueProvider` is a protocol that return animation data for a property at a
/// given time. Every frame an `AnimationView` queries all of its properties and asks
/// if their ValueProvider has an update. If it does the AnimationView will read the
/// property and update that portion of the animation.
///
/// Value Providers can be used to dynamically set animation properties at run time.
public protocol AnyValueProvider {
/// The Type of the value provider
var valueType: Any.Type { get }
/// The type-erased storage for this Value Provider
var typeErasedStorage: AnyValueProviderStorage { get }
/// Asks the provider if it has an update for the given frame.
func hasUpdate(frame: AnimationFrameTime) -> Bool
}
extension AnyValueProvider {
/// Asks the provider to update the container with its value for the frame.
public func value(frame: AnimationFrameTime) -> Any {
typeErasedStorage.value(frame: frame)
}
}
// MARK: - ValueProvider
/// A base protocol for strongly-typed Value Providers
protocol ValueProvider: AnyValueProvider {
associatedtype Value: AnyInterpolatable
/// The strongly-typed storage for this Value Provider
var storage: ValueProviderStorage<Value> { get }
}
extension ValueProvider {
public var typeErasedStorage: AnyValueProviderStorage {
switch storage {
case .closure(let typedClosure):
return .closure(typedClosure)
case .singleValue(let typedValue):
return .singleValue(typedValue)
case .keyframes(let keyframes):
return .keyframes(
keyframes.map { keyframe in
keyframe.withValue(keyframe.value as Any)
},
interpolate: storage.value(frame:))
}
}
}
// MARK: - ValueProviderStorage
/// The underlying storage of a `ValueProvider`
public enum ValueProviderStorage<T: AnyInterpolatable> {
/// The value provider stores a single value that is used on all frames
case singleValue(T)
/// The value provider stores a group of keyframes
/// - The main-thread rendering engine interpolates values in these keyframes
/// using `T`'s `Interpolatable` implementation.
/// - The Core Animation rendering engine constructs a `CAKeyframeAnimation`
/// using these keyframes. The Core Animation render server performs
/// the interpolation, without calling `T`'s `Interpolatable` implementation.
case keyframes([Keyframe<T>])
/// The value provider stores a closure that is invoked on every frame
/// - This is only supported by the main-thread rendering engine
case closure((AnimationFrameTime) -> T)
// MARK: Internal
func value(frame: AnimationFrameTime) -> T {
switch self {
case .singleValue(let value):
return value
case .closure(let closure):
return closure(frame)
case .keyframes(let keyframes):
return KeyframeInterpolator(keyframes: ContiguousArray(keyframes)).storage.value(frame: frame)
}
}
}
// MARK: - AnyValueProviderStorage
/// A type-erased representation of `ValueProviderStorage`
public enum AnyValueProviderStorage {
/// The value provider stores a single value that is used on all frames
case singleValue(Any)
/// The value provider stores a group of keyframes
/// - Since we can't interpolate a type-erased `KeyframeGroup`,
/// the interpolation has to be performed in the `interpolate` closure.
case keyframes([Keyframe<Any>], interpolate: (AnimationFrameTime) -> Any)
/// The value provider stores a closure that is invoked on every frame
case closure((AnimationFrameTime) -> Any)
// MARK: Internal
func value(frame: AnimationFrameTime) -> Any {
switch self {
case .singleValue(let value):
return value
case .closure(let closure):
return closure(frame)
case .keyframes(_, let valueForFrame):
return valueForFrame(frame)
}
}
}