Here is my working codes for callBack of CABasicAnimation when the animation is Done. I am given the needed action to animation delegate, but what I want to be able do this work on sub class of CABasicAnimation:
extension NSView {
func fadeAnimation(callBack: @escaping () -> Void) {
let animation = CABasicAnimation()
animation.delegate = CustomCAAnimationDelegate(callBack: callBack)
animation.keyPath = "opacity"
animation.duration = 2.0
animation.fromValue = 1.0
animation.toValue = 0.0
animation.timingFunction = CAMediaTimingFunction(name: .linear)
animation.isRemovedOnCompletion = false
animation.fillMode = .forwards
self.layer?.add(animation, forKey: nil)
}
}
class CustomCAAnimationDelegate: NSObject, CAAnimationDelegate {
var callBack: () -> Void
init(callBack: @escaping () -> Void) {
self.callBack = callBack
}
internal func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
callBack()
}
}
So the goal is having some code like this:
class CustomCABasicAnimation: CABasicAnimation {
var callBack: () -> Void
}
which if that is done I would be able to code like this:
extension NSView {
func fadeAnimation(callBack: @escaping () -> Void) {
let animation = CustomCABasicAnimation()
animation.callBack = callBack
// The other codes ...
}
}
I have implemented my custom animation class as follows:
class CustomCABasicAnimation: CABasicAnimation {
var callBack: () -> Void
init(callBack: @escaping () -> Void) {
self.callBack = callBack
super.init()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
When I run my code I get the error:
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
and:
Fade_Test/ViewController.swift:57: Fatal error: Use of unimplemented initializer 'init()' for class 'Fade_Test.CustomCABasicAnimation' 2023-03-17 23:39:59.577008+0100 Fade Test[1810:79953] Fade_Test/ViewController.swift:57: Fatal error: Use of unimplemented initializer 'init()' for class 'Fade_Test.CustomCABasicAnimation'
It turns out that extending CABasicAnimation
isn't as straightforward as it would seem.
You can't really add your own initializer. The documentation for CABasicAnimation
states:
You create an instance of CABasicAnimation using the inherited init(keyPath:) method, specifying the key path of the property to be animated in the render tree.
So really your CustomCABasicAnimation
can only add the new property, but no initializer. This means your callBack
property must be optional.
class CustomCABasicAnimation: CABasicAnimation {
var callBack: (() -> Void)?
}
You can add/override other methods as needed to make use of the optional callBack
.
Now your creation of the CustomCABasicAnimation
will have to look more like this:
let animation = CustomCABasicAnimation(keyPath: "opacity")
animation.callBack = callBack
// other properties as needed