I have a CALayer with a custom animation on it, working via an @NSManaged
property, and overriding:
class func defaultValue(forKey key: String) -> Any?
class func needsDisplay(forKey key: String) -> Bool
func action(forKey key: String) -> CAAction?
func display()
However, I sometimes want to bypass the animation and have the property immediately step to the new value. In my CALayer
sub-class I tried this:
@NSManaged private var radius: CGFloat
func animate(to radius: CGFloat) {
self.radius = radius
}
func step(to radius: CGFloat) {
// Inspired by https://stackoverflow.com/a/34941743
CATransaction.begin()
CATransaction.setDisableActions(true) // Prevents animation occurring
self.radius = radius
CATransaction.commit()
setNeedsDisplay() // Has no effect
}
When animate(to:)
is called, display()
is called repeatedly and my custom drawing code can do it's thing. When step(to:)
is called, the CATransaction
code does prevent an animation from occurring, but no drawing is ever performed at all.
I can get it to behave as desired, but it feels quite hacky:
func step(to radius: CGFloat) {
// func action(forKey key: String) -> CAAction? uses .animationDuration
// when constructing a CABasicAnimation
let duration = animationDuration
defer { animationDuration = duration }
animationDuration = 0
self.radius = radius
}
What is the correct method to give the caller the ability to choose whether the property animates from one value to the next, or steps immediately? A subsequent change to radius
should respect the previous value, whether it was stepped or animated to.