我有一个绘制圆弧的自定义 CALayer
子类。它看起来像:
class ArcLayer: CALayer {
var strokeColor:UIColor = UIColor.blackColor() { didSet { self.setNeedsDisplay() }}
var strokeWidth:CGFloat = 1.0 { didSet { self.setNeedsDisplay() }}
var strokeCap:CGLineCap = .Butt { didSet { self.setNeedsDisplay() }}
var startRadians:CGFloat = 0.0 { didSet { self.setNeedsDisplay() }}
var sweepRadians:CGFloat = Tau { didSet { self.setNeedsDisplay() }}
// other init's omitted for brevity
override init(layer: AnyObject) {
super.init(layer: layer)
if let layer = layer as? ArcLayer {
self.strokeColor = layer.strokeColor
self.strokeWidth = layer.strokeWidth
self.strokeCap = layer.strokeCap
self.startRadians = layer.startRadians
self.sweepRadians = layer.sweepRadians
}
}
override func drawInContext(ctx: CGContext) {
...
}
override class func needsDisplayForKey(key: String) -> Bool {
return key == "startRadians" || key == "sweepRadians" || super.needsDisplayForKey(key)
}
}
我正在使用自定义子类,因为虽然 CAShapeLayer
的 path
是可动画的,但它不会以您期望的圆弧旋转方式进行动画处理.以上作品。开始/扫描的动画产生了预期的效果。
虽然我想改变它。我有一个 Angle
结构(参见 this answer ),我宁愿使用它也不愿使用原始弧度 CGFloat 值。将这两个变量的类型更改为 Angle
编译正常。原始显示也有效(在从 Angle
vars 进行适当的转换/提取之后)。问题是现在能够为这些变量设置动画。和以前一样,我可能会编写一些代码,例如:
let sweep = CABasicAnimation(keyPath: "sweepRadians")
sweep.fromValue = 0.0 // raw radians value
sweep.toValue = Tau // raw radians value for one rotation
sweep.duration = 10.seconds
sweep.repeatCount = 0
self.blueRing.addAnimation(sweep, forKey: "sweepRadians")
我不能只将它们更改为 Angle
值:
sweep.fromValue = Angle(raw: 0, unit: .Rotations)
sweep.toValue = Angle(raw: 0, unit: .Rotations)
结果是
cannot assign value of type 'Angle' to type of 'AnyObject?'
我希望解决方案是我需要以某种方式将我的 Angle
值转换/包装为 NSValue 对象?那确实是正确的吗?可以吗?怎么会这样?
我真的很喜欢 Swift,但是它与 Objc 交叉的极端情况真的很令人困惑。
最佳答案
Angle
是一个结构体,不符合AnyObject
。为了符合AnyObject
,需要把它改成一个类,或者像Box
一样包装成一个类:
final class Box<T> {
let value: T
init(_ value: T) { self.value = value }
}
也就是说,这不太可能奏效。 CABasicAnimation
有关于如何 interpolate specific things 的特殊知识:
- 整数和双数
- CGRect、CGPoint、CGSize 和 CGAffineTransform 结构
- CATransform3D 数据结构
- CGColor 和 CGImage 引用
我认为没有任何方法可以添加到此列表中。我不相信您可以使用 CABasicAnimation
来插入任意类型。您需要从一个数字到另一个数字进行动画处理,因此这基本上就是您上面的代码。
当然你可以让 sweepRadians
成为一个计算属性,它只是转发给 sweep
,你可以从 Degrees(0).rawRadians
到 Degrees(360).rawRadians
。这样你就可以获得大部分你想要的实际 yield ;只是在某些时候需要手动转换为数字。
现在,如果这是 Mac,您可以子类化 NSAnimation
并构建您自己的动画师来执行此操作。参见 CABasicAnimation and custom types讨论那个。但是 iOS 上没有 NSAnimation
,我不相信你可以用同样的方式子类化 CAAnimation
。 CAAnimation
上没有“进度”委托(delegate)方法。
关于swift - 出于 CAAnimation 的目的将 Swift 结构转换/包装为 NSValue?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32893429/