问题描述
当我寻找CALayer动画时,我发现了类似的解决方案:
let basicAnimation = CABasicAnimation(keyPath: "opacity")
basicAnimation.fromValue = 0
basicAnimation.tovalue = 1
basicAnimation.duration = 0.3
add(basicAnimation,forKey: "opacity")
但是fromValue和tovalue是Any的类型,并且作为键,我们可以使用任何字符串,这是不安全的。使用最新的Swift功能有更好的方法吗?
解决方法
我想出了使用非常简单的解决方案:
layer.animate(.init(
keyPath: \.opacity,value: "1",// this will produce an error
duration: 0.3)
)
layer.animate(.init(
keyPath: \.opacity,value: 1,// correct
duration: 0.3)
)
layer.animate(.init(
keyPath: \.backgroundColor,value: UIColor.red,// this will produce an error
duration: 0.3,timingFunction: .init(name: .easeOut),beginFromCurrentState: true)
)
layer.animate(.init(
keyPath: \.backgroundColor,value: UIColor.red.cgColor,// correct
duration: 0.3,beginFromCurrentState: true)
)
解决方案代码为:
import QuartzCore
extension CALayer {
struct Animation<Value> {
let keyPath: ReferenceWritableKeyPath<CALayer,Value>
let value: Value
let duration: TimeInterval
let timingFunction: CAMediaTimingFunction? = nil
let beginFromCurrentState = false
}
@discardableResult func animate<Value>(
_ animation: Animation<Value>,completionHandler: (() -> Void)? = nil)
-> CABasicAnimation?
{
CATransaction.begin()
CATransaction.setCompletionBlock(completionHandler)
defer {
// update actual value with the final one
self[keyPath: animation.keyPath] = animation.value
CATransaction.commit()
}
guard animation.duration > 0 else { return nil }
let fromValueLayer: CALayer
if animation.beginFromCurrentState,let presentation = presentation() {
fromValueLayer = presentation
} else {
fromValueLayer = self
}
let basicAnimation = CABasicAnimation(
keyPath: NSExpression(forKeyPath: animation.keyPath).keyPath
)
basicAnimation.timingFunction = animation.timingFunction
basicAnimation.fromValue = fromValueLayer[keyPath: animation.keyPath]
basicAnimation.toValue = animation.value
basicAnimation.duration = animation.duration
add(basicAnimation,forKey: basicAnimation.keyPath)
return basicAnimation
}
}
优点:
- 在CALayer上可用的keyPath自动补全
- 值类型取决于keyPath,因此您将无法设置错误的值
- 清除代码
缺点:
- 我们仍然可以选择不可设置动画的keyPath