4

我有一个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)
    }
}

我正在使用自定义子类,因为虽然pathaCAShapeLayer是可动画的,但它不会以您期望圆弧旋转的方式动画。以上工作。开始/扫描的动画会产生所需的效果。

我想改变它。我有一个Angle结构(见这个答案),我宁愿使用它而不是原始弧度 CGFloat 值。将这两个变量的类型更改为可以Angle正常编译。Angle并且原始显示也有效(在从变量中进行适当的转换/提取之后)。问题是现在能够为这些变量设置动画。和以前一样,我可能已经编写了一些代码,例如:

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 相交的极端情况可能真的很令人困惑。

4

2 回答 2

3

Angle是一个结构,它不符合AnyObject. 为了符合AnyObject,您需要将其更改为一个类,或将其包装到一个类中,例如Box

final class Box<T> {
    let value: T
    init(_ value: T) { self.value = value }
}

也就是说,这不太可能奏效。对如何插入特定事物CABasicAnimation有特殊的了解:

  • 整数和双精度数
  • CGRect、CGPoint、CGSize 和 CGAffineTransform 结构
  • CATransform3D 数据结构
  • CGColor 和 CGI​​mage 参考

我不相信有任何方法可以添加到此列表中。我不相信你可以CABasicAnimation用来插入任意类型。你需要从一个数字动画到一个数字,所以这基本上就是你上面的代码。

当然,您可以将sweepRadians其设为只转发到的计算属性,并且您可以对 from to 进行sweep动画处理。这样您就可以获得大部分您想要的实际收益;只是不是没有在某个时候手动转换为数字。Degrees(0).rawRadiansDegrees(360).rawRadians

现在,如果这是 Mac,您可以子类化NSAnimation并构建自己的动画师来执行此操作。请参阅CABasicAnimation 和自定义类型以进行讨论。但是NSAnimation在 iOS 上没有,我不相信你可以CAAnimation以同样的方式进行子类化。上没有“进度”委托方法CAAnimation

于 2015-10-01T19:02:59.880 回答
0

我认为你应该尝试使用init(pointer pointer: UnsafePointer<Void>)of NSValue。您可以使用获取指向您的Angle实例的指针func withUnsafePointer<T, Result>(inout arg: T, @noescape _ body: UnsafePointer<T> throws -> Result) rethrows -> Result(参见http://swiftdoc.org/v2.0/func/withUnsafePointer/以供参考)。PS 将 NSValue 包装的东西传递给 Core Animation 的想法通常是一种可行的技术。不过,目前还不清楚 CA 是否会解开 Angle。祝你好运。

于 2015-10-01T19:42:04.360 回答