【问题标题】:Convert/Wrap Swift struct as NSValue for CAAnimation purposes?为 CAAnimation 目的将 Swift 结构转换/包装为 NSValue?
【发布时间】: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)
    }
}

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

我想改变它。我有一个 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 相交的极端情况可能真的很令人困惑。

【问题讨论】:

    标签: swift struct swift2 caanimation nsvalue


    【解决方案1】:

    Angle 是一个结构体,不符合AnyObject。为了符合AnyObject,需要改成一个类,或者像Box这样包装成一个类:

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

    也就是说,这不太可能奏效。 CABasicAnimationinterpolate specific things有专门的了解:

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

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

    当然,您可以使 sweepRadians 成为仅转发到 sweep 的计算属性,并且您可以从 Degrees(0).rawRadians 动画到 Degrees(360).rawRadians。这样您就可以获得大部分您想要的实际收益;只是不是没有在某个时候手动转换为数字。

    现在,如果这是 Mac,您可以继承 NSAnimation 并构建自己的动画师来执行此操作。请参阅CABasicAnimation and custom types 进行讨论。但是iOS上没有NSAnimation,我不相信你可以用同样的方式继承CAAnimationCAAnimation 上没有“进度”委托方法。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多