Commit 14e27b97 by Orkhan Alikhanov

Changed to updating model before firing animations

This way we no longer need CAAnimationDelegate to
listen to animationDidStop in order to update the model
and remove animation after it's done. We update the model
in advance, and system just removes the animation on completion

Also fixes animation group not removed from layer after completion
parent 2d0d4397
......@@ -25,9 +25,6 @@
import UIKit
@available(iOS 10, *)
extension CALayer: CAAnimationDelegate {}
internal extension CALayer {
/// Swizzle the `add(_:forKey:) selector.
internal static var motionAddedAnimations: [(CALayer, String, CAAnimation)]? = {
......@@ -110,14 +107,11 @@ public extension CALayer {
*/
func animate(_ animations: [CAAnimation]) {
for animation in animations {
if nil == animation.delegate {
animation.delegate = self
}
if let a = animation as? CABasicAnimation {
a.fromValue = (presentation() ?? self).value(forKeyPath: a.keyPath!)
}
updateModel(animation)
if let a = animation as? CAPropertyAnimation {
add(a, forKey: a.keyPath!)
} else if let a = animation as? CAAnimationGroup {
......@@ -129,46 +123,6 @@ public extension CALayer {
}
/**
Executed when an animation has started.
- Parameter _ anim: A CAAnimation.
*/
func animationDidStart(_ anim: CAAnimation) {}
/**
A delegation function that is executed when the backing layer stops
running an animation.
- Parameter animation: The CAAnimation instance that stopped running.
- Parameter flag: A boolean that indicates if the animation stopped
because it was completed or interrupted. True if completed, false
if interrupted.
*/
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
guard let a = anim as? CAPropertyAnimation else {
if let a = (anim as? CAAnimationGroup)?.animations {
for x in a {
animationDidStop(x, finished: true)
}
}
return
}
guard let b = a as? CABasicAnimation else {
return
}
guard let v = b.toValue else {
return
}
guard let k = b.keyPath else {
return
}
setValue(v, forKeyPath: k)
removeAnimation(forKey: k)
}
/**
A function that accepts a list of MotionAnimation values and executes them.
- Parameter animations: A list of MotionAnimation values.
*/
......@@ -321,11 +275,7 @@ fileprivate extension CALayer {
}
}
let g = Motion.animate(group: anims, duration: duration)
g.fillMode = .both
g.isRemovedOnCompletion = false
g.timingFunction = ts.timingFunction
let g = Motion.animate(group: anims, timingFunction: ts.timingFunction, duration: duration)
self.animate(g)
if let v = ts.completion {
......@@ -338,3 +288,19 @@ fileprivate extension CALayer {
}
}
}
private extension CALayer {
/**
Updates the model with values provided in animation.
- Parameter animation: A CAAnimation.
*/
func updateModel(_ animation: CAAnimation) {
if let a = animation as? CABasicAnimation {
setValue(a.toValue, forKeyPath: a.keyPath!)
} else if let a = animation as? CAAnimationGroup {
a.animations?.forEach {
updateModel($0)
}
}
}
}
......@@ -207,8 +207,6 @@ extension Motion {
*/
public class func animate(group animations: [CAAnimation], timingFunction: CAMediaTimingFunction = .easeInOut, duration: CFTimeInterval = 0.5) -> CAAnimationGroup {
let group = CAAnimationGroup()
group.fillMode = .both
group.isRemovedOnCompletion = false
group.animations = animations
group.duration = duration
group.timingFunction = timingFunction
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment