[英]How to optionally animate property of a CALayer with custom animation
I have a CALayer with a custom animation on it, working via an @NSManaged
property, and overriding:我有一个带有自定义 animation 的 CALayer,通过
@NSManaged
属性工作,并覆盖:
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.但是,有时我想绕过 animation 并让属性立即进入新值。 In my
CALayer
sub-class I tried this:在我的
CALayer
子类中,我尝试了这个:
@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.当调用
animate(to:)
时,会重复调用display()
并且我的自定义绘图代码可以做到这一点。 When step(to:)
is called, the CATransaction
code does prevent an animation from occurring, but no drawing is ever performed at all.当调用
step(to:)
时, CATransaction
代码确实阻止了 animation 的发生,但根本没有执行任何绘图。
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.随后对
radius
的更改应遵循先前的值,无论是步进还是动画。
You say you have implemented action(forKey:)
(quite rightly).你说你已经实施了
action(forKey:)
(非常正确)。 So on those occasions when you don't want this property to be animated, return nil
from that method.所以在那些你不希望这个属性被动画化的情况下,从那个方法返回
nil
。 The drawing will still take place, but without animation.绘图仍将进行,但没有 animation。
Alternatively, you could return super.action(forKey:key)
.或者,您可以返回
super.action(forKey:key)
。 That might be a little more sane, but the outcome is the same.这可能更理智一点,但结果是一样的。
You may ask (and I hope you do): How can I throw some kind of switch that action(forKey:)
can consult in order to know which kind of occasion this is?你可能会问(我希望你会问):我怎样才能抛出某种开关,让
action(forKey:)
可以参考以了解这是哪种情况? One possibility is to set a property of the layer using key-value coding.一种可能性是使用键值编码设置层的属性。
CALayer has a wonderful feature that you are allowed to call setValue(_:forKey:)
or value(forKey:)
for any key; CALayer 有一个很棒的特性,你可以为任何键调用
setValue(_:forKey:)
或value(forKey:)
; it doesn't have to be a "real" key that already exists.它不一定是已经存在的“真实”密钥。
So you could call setValue(false, forKey:"shouldAnimate")
on the layer before setting the property.因此,您可以在设置属性之前在图层上调用
setValue(false, forKey:"shouldAnimate")
。 And your action(forKey:)
can then consult value(forKey:"shouldAnimate")
, and see whether it is false
(as opposed to true
or nil
) — and if it is, it returns nil
to prevent the animation.然后你的
action(forKey:)
可以查询value(forKey:"shouldAnimate")
,看看它是否为false
(相对于true
或nil
)——如果是,它返回nil
以防止 animation。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.