[英]How to optionally animate property of a CALayer with custom animation
我有一个带有自定义 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()
但是,有时我想绕过 animation 并让属性立即进入新值。 在我的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
}
当调用animate(to:)
时,会重复调用display()
并且我的自定义绘图代码可以做到这一点。 当调用step(to:)
时, CATransaction
代码确实阻止了 animation 的发生,但根本没有执行任何绘图。
我可以让它按预期运行,但感觉很老套:
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
}
使调用者能够选择属性是从一个值到下一个值还是立即执行动画的正确方法是什么? 随后对radius
的更改应遵循先前的值,无论是步进还是动画。
你说你已经实施了action(forKey:)
(非常正确)。 所以在那些你不希望这个属性被动画化的情况下,从那个方法返回nil
。 绘图仍将进行,但没有 animation。
或者,您可以返回super.action(forKey:key)
。 这可能更理智一点,但结果是一样的。
你可能会问(我希望你会问):我怎样才能抛出某种开关,让action(forKey:)
可以参考以了解这是哪种情况? 一种可能性是使用键值编码设置层的属性。
CALayer 有一个很棒的特性,你可以为任何键调用setValue(_:forKey:)
或value(forKey:)
; 它不一定是已经存在的“真实”密钥。
因此,您可以在设置属性之前在图层上调用setValue(false, forKey:"shouldAnimate")
。 然后你的action(forKey:)
可以查询value(forKey:"shouldAnimate")
,看看它是否为false
(相对于true
或nil
)——如果是,它返回nil
以防止 animation。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.