将CA动画化的Swift结构转换/包装为NSValue吗? [英] Convert/Wrap Swift struct as NSValue for CAAnimation purposes?

查看:165
本文介绍了将CA动画化的Swift结构转换/包装为NSValue吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义的CALayer子类,该子类绘制了圆弧.看起来像这样:

I have a custom CALayer subclass that draws a circular arc. It looks something like:

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是可动画的,但它不会以您期望弧线旋转的方式进行动画处理.以上作品.开始/扫动的动画会产生所需的效果.

I'm using a custom subclass, because while the path of a CAShapeLayer is animatable, it does not animate in the way you would expect the arc to rotate around. The above works. Animations to the start/sweep produce the desired effect.

我想更改它.我有一个Angle结构(请参阅此答案),我宁愿使用原始的弧度CGFloat值.将这两个变量的类型更改为Angle可以正常编译.并且原始显示也可以工作(在Angle变量中进行适当的转换/提取之后).现在的问题是可以为这些var设置动画.和以前一样,我可能会写一些像这样的代码:

I want to change it though. I have an Angle struct (see this answer) which I would rather use than the raw radian CGFloat value. Changing the type of those two vars to Angle compiles fine. And the original display works too (after making the appropriate conversions/extractions from the Angle vars). THE PROBLEM is being able to animate those vars now. Where as before I might have written some code like:

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值:

I can't just change those to Angle values:

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对象?确实正确吗?能做到吗怎么这样?

I'm hoping that the solution is that I need to somehow convert/wrap my Angle values as NSValue objects? Is that indeed correct? Can it be done? How so?

我真的很喜欢Swift,但是它与Objc相交的极端情况确实令人困惑.

I really like Swift, but the corner cases where it intersects with Objc can be really confusing.

推荐答案

Angle是不符合AnyObject的结构.为了符合AnyObject,您需要将其更改为一个类,或将其包装为类似Box的类:

Angle is a struct, which does not conform to AnyObject. In order to conform to AnyObject, you need to change it to a class, or wrap it into a class like Box:

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

也就是说,这不太可能奏效. CABasicAnimation具有有关如何插值的特殊知识.具体内容:

That said, this is unlikely to work. CABasicAnimation has special knowledge about how to interpolate specific things:

  • 整数和双打
  • CGRect,CGPoint,CGSize和CGAffineTransform结构
  • CATransform3D数据结构
  • CGColor和CGImage参考

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

I don't believe there's any way to add to this list. I don't believe you can use CABasicAnimation to interpolate arbitrary types. You need to animate from a number to a number, so that's going to be basically the code you have above.

当然,您可以将sweepRadians设置为仅转发到sweep的计算属性,并且可以将Degrees(0).rawRadians动画化为Degrees(360).rawRadians.因此,您可以获得所需的大多数实际好处;只是在某些时候没有手动转换为数字.

Of course you can make sweepRadians be a computed property that just forwards to sweep, and you could animate from Degrees(0).rawRadians to Degrees(360).rawRadians. So you can get most of the practical benefits you want; just not without manually converting to a number at some point.

现在,如果这是Mac,则可以继承NSAnimation的子类,并构建自己的动画师来执行此操作.请参阅 CABasicAnimation和自定义类型.但是iOS上没有NSAnimation,而且我不相信您可以用相同的方式继承CAAnimation的子类. CAAnimation上没有进度"委托方法.

Now if this is Mac, you can subclass NSAnimation and build your own animator that can do this. See CABasicAnimation and custom types for discussion of that. But there's no NSAnimation on iOS, and I don't believe you can subclass CAAnimation in the same way. There's no "progress" delegate method on CAAnimation.

这篇关于将CA动画化的Swift结构转换/包装为NSValue吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆