为 CAAnimation 目的将 Swift 结构转换/包装为 NSValue?
Posted
技术标签:
【中文标题】为 CAAnimation 目的将 Swift 结构转换/包装为 NSValue?【英文标题】:Convert/Wrap Swift struct as NSValue for CAAnimation purposes? 【发布时间】:2015-10-01 17:29:46 【问题描述】:我有一个自定义的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 相交的极端情况可能真的很令人困惑。
【问题讨论】:
【参考方案1】:Angle
是一个结构体,不符合AnyObject
。为了符合AnyObject
,需要改成一个类,或者像Box
这样包装成一个类:
final class Box<T>
let value: T
init(_ value: T) self.value = value
也就是说,这不太可能奏效。 CABasicAnimation
对interpolate specific things有专门的了解:
我不相信有任何方法可以添加到此列表中。我不相信您可以使用 CABasicAnimation
来插入任意类型。你需要从一个数字动画到一个数字,所以这基本上就是你上面的代码。
当然,您可以使 sweepRadians
成为仅转发到 sweep
的计算属性,并且您可以从 Degrees(0).rawRadians
动画到 Degrees(360).rawRadians
。这样您就可以获得大部分您想要的实际收益;只是不是没有在某个时候手动转换为数字。
现在,如果这是 Mac,您可以继承 NSAnimation
并构建自己的动画师来执行此操作。请参阅CABasicAnimation and custom types 进行讨论。但是ios上没有NSAnimation
,我不相信你可以用同样的方式继承CAAnimation
。 CAAnimation
上没有“进度”委托方法。
【讨论】:
【参考方案2】:我认为你应该尝试使用init(pointer pointer: UnsafePointer<Void>)
of NSValue
。您可以使用func withUnsafePointer<T, Result>(inout arg: T, @noescape _ body: UnsafePointer<T> throws -> Result) rethrows -> Result
获取指向您的Angle
实例的指针(参见http://swiftdoc.org/v2.0/func/withUnsafePointer/ 以供参考)。
附:将 NSValue 包装的东西传递给 Core Animation 的想法通常是一种可行的技术。不过,目前还不清楚 CA 是否会解开 Angle。祝你好运。
【讨论】:
以上是关于为 CAAnimation 目的将 Swift 结构转换/包装为 NSValue?的主要内容,如果未能解决你的问题,请参考以下文章
CAAnimation 在 CALayer 上没有按预期工作