1
1
mirror of https://github.com/exyte/Macaw.git synced 2024-11-13 13:14:20 +03:00
Macaw/Source/animation/AnimationImpl.swift
2018-02-12 19:27:36 +07:00

277 lines
6.6 KiB
Swift

//
// AnimationImpl.swift
// Pods
//
// Created by Yuri Strot on 9/2/16.
//
//
import Foundation
enum AnimationType {
case unknown
case contents
case affineTransformation
case opacity
case sequence
case combine
case morphing
case shape
case empty
}
class BasicAnimation: Animation {
var nodeId: String?
var type = AnimationType.unknown
let ID: String
var next: BasicAnimation?
var removeFunc: (() -> Void)?
var delayed = false
var manualStop = false
var paused = false
var pausedProgress = 0.0
var progress = 0.0
var repeatCount = 0.0
var cycled = false
var delay = 0.0
var autoreverses = false
var onProgressUpdate: ((Double) -> Void)?
var easing = Easing.ease
var completion: (() -> Void)?
override init() {
ID = UUID().uuidString
super.init()
}
override open func delay(_ delay: Double) -> Animation {
self.delay += delay
return self
}
override open func cycle(_ count: Double) -> Animation {
self.repeatCount = count
return self
}
override open func easing(_ easing: Easing) -> Animation {
self.easing = easing
return self
}
override open func autoreversed() -> Animation {
self.autoreverses = true
return self
}
override open func cycle() -> Animation {
self.cycled = true
return self
}
override open func onComplete(_ f: @escaping (() -> Void)) -> Animation {
self.completion = f
return self
}
override open func play() {
manualStop = false
paused = false
animationProducer.addAnimation(self)
}
override open func stop() {
manualStop = true
paused = false
if delay > 0.0 {
animationProducer.removeDelayed(animation: self)
}
removeFunc?()
}
override open func pause() {
paused = true
manualStop = false
if delay > 0.0 {
animationProducer.removeDelayed(animation: self)
}
removeFunc?()
}
override func state() -> AnimationState {
if delayed {
return .running
}
if self.progress == 0.0 {
return .initial
}
if paused || manualStop || progress == 1.0 {
return .paused
}
return .running
}
override open func reverse() -> Animation {
return self
}
func getDuration() -> Double { return 0 }
}
// MARK: - Hashable
extension BasicAnimation: Hashable {
public var hashValue: Int {
return ID.hashValue
}
public static func == (lhs: BasicAnimation, rhs: BasicAnimation) -> Bool {
return lhs.ID == rhs.ID
}
}
// MARK: - Activity
extension BasicAnimation {
func isActive() -> Bool {
return progress > 0.0 && progress < 1.0
}
}
// Animated property list https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreAnimation_guide/AnimatableProperties/AnimatableProperties.html
internal class AnimationImpl<T: Interpolable>: BasicAnimation {
var variable: AnimatableVariable<T>
let initialValue: T
let timeFactory: (() -> ((Double) -> T))
let duration: Double
let logicalFps: UInt
private var vFunc: ((Double) -> T)?
init(observableValue: AnimatableVariable<T>, valueFunc: @escaping (Double) -> T, animationDuration: Double, delay: Double = 0.0, fps: UInt = 30) {
self.variable = observableValue
self.initialValue = observableValue.value
self.duration = animationDuration
self.timeFactory = { return valueFunc }
self.vFunc = .none
self.logicalFps = fps
super.init()
self.delay = delay
}
init(observableValue: AnimatableVariable<T>, factory: @escaping (() -> ((Double) -> T)), animationDuration: Double, delay: Double = 0.0, fps: UInt = 30) {
self.variable = observableValue
self.initialValue = observableValue.value
self.duration = animationDuration
self.timeFactory = factory
self.logicalFps = fps
super.init()
self.delay = delay
}
convenience init(observableValue: AnimatableVariable<T>, startValue: T, finalValue: T, animationDuration: Double) {
let interpolationFunc = { (t: Double) -> T in
return startValue.interpolate(finalValue, progress: t)
}
self.init(observableValue: observableValue, valueFunc: interpolationFunc, animationDuration: animationDuration)
}
convenience init(observableValue: AnimatableVariable<T>, finalValue: T, animationDuration: Double) {
self.init(observableValue: observableValue, startValue: observableValue.value, finalValue: finalValue, animationDuration: animationDuration)
}
override open func play() {
if manualStop {
variable.value = getVFunc()(0.0)
}
if paused {
variable.value = getVFunc()(pausedProgress)
}
super.play()
}
open override func getDuration() -> Double {
var totalDuration = autoreverses ? duration * 2.0 : duration
totalDuration = totalDuration * (1.0 - pausedProgress)
return totalDuration
}
open func getVFunc() -> ((Double) -> T) {
if let vFunc = vFunc {
return vFunc
}
var timeFunc = { (t: Double) -> Double in
return t
}
if autoreverses {
let original = timeFunc
timeFunc = { (t: Double) -> Double in
if t <= 0.5 {
return original(t * 2.0)
} else {
return original((1.0 - t) * 2.0)
}
}
}
let timeFactory = self.timeFactory()
vFunc = { (t: Double) -> T in
return timeFactory(timeFunc(t))
}
return vFunc!
}
}
// For sequence completion
class EmptyAnimation: BasicAnimation {
required init(completion: @escaping (() -> Void)) {
super.init()
self.completion = completion
self.type = .empty
}
}
// MARK: - Animation Description
open class AnimationDescription <T> {
open let valueFunc: (Double) -> T
open var duration = 0.0
open var delay = 0.0
public init(valueFunc: @escaping (Double) -> T, duration: Double = 1.0, delay: Double = 0.0) {
self.valueFunc = valueFunc
self.duration = duration
self.delay = delay
}
open func t(_ duration: Double, delay: Double = 0.0) -> AnimationDescription<T> {
return AnimationDescription(valueFunc: valueFunc, duration: duration, delay: delay)
}
}