swift - 出于 CAAnimation 的目的将 Swift 结构转换/包装为 NSValue?

标签 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)
    }
}

我正在使用自定义子类,因为虽然 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 交叉的极端情况真的很令人困惑。

最佳答案

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 和 CGI​​mage 引用

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

当然你可以让 sweepRadians 成为一个计算属性,它只是转发给 sweep,你可以从 Degrees(0).rawRadiansDegrees(360).rawRadians。这样你就可以获得大部分你想要的实际 yield ;只是在某些时候需要手动转换为数字。

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

关于swift - 出于 CAAnimation 的目的将 Swift 结构转换/包装为 NSValue?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32893429/

相关文章:

ios - 数组更改时 SwiftUI 列表不更新

ios - 触摸外部时如何更改按钮字体?

c - 动态分配结构体数组 C

swift - 不是在模拟器上而是在 iPhone 上出现错误 "Will attempt to recover by breaking"

swift - 使用 Swift 替换文件系统中的文件夹

ios - 如何在 Swift 中通过参数比较来美化枚举?

ios - 使用 SwiftCharts 框架时图形 View 超出范围

swift - 如何在 macOs 中禁用键盘输入?

c - 链接列表向后显示

c++ - 如何在头文件中定义具有继承性的结构?