转换/包装Swift结构作为NSValue用于CAAnimation目的?

时间:2015-10-01 17:29:47

标签: swift struct swift2 caanimation nsvalue

我有一个绘制圆弧的自定义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)
    }
}

我使用的是自定义子类,因为虽然path的{​​{1}}是可动画的,但它并不像您期望弧旋转的那样动画。以上工作。开始/扫描的动画产生所需的效果。

我想改变它。我有一个CAShapeLayer结构(参见this answer)我宁愿使用它而不是原始弧度CGFloat值。将这两个变量的类型更改为Angle编译正常。并且原始显示也有效(在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?' 值转换/包装为NSValue对象?那确实是对的吗?可以吗?怎么样?

我真的很喜欢斯威夫特,但与Objc相交的角落情况可能会令人困惑。

2 个答案:

答案 0 :(得分:1)

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。因此,您可以获得您想要的大部分实际好处;只是在某些时候没有手动转换为数字。

现在如果这是Mac,你可以继承NSAnimation并构建你自己的动画师,可以做到这一点。有关详细信息,请参阅CABasicAnimation and custom types。但iOS上没有NSAnimation,我不相信你可以以同样的方式继承CAAnimationCAAnimation上没有“进度”委托方法。

答案 1 :(得分:0)

我认为您应该尝试使用init(pointer pointer: UnsafePointer<Void>)的{​​{1}}。您可以使用NSValue获取指向Angle实例的指针(请参阅http://swiftdoc.org/v2.0/func/withUnsafePointer/以供参考)。 附:将NSValue包装的东西传递给Core Animation的想法一般是一种工作技术。目前还不清楚CA是否会打开角度。祝你好运。