Ios 在计算过程中修改值

Ios 在计算过程中修改值,ios,swift,caanimation,Ios,Swift,Caanimation,假设你有一个简单的动画 let e : CABasicAnimation = CABasicAnimation(keyPath: "strokeEnd") e.duration = 2.0 e.fromValue = 0 e.toValue = 1.0 e.repeatCount = .greatestFiniteMagnitude self.someLayer.add(e, forKey: nil) 一层的 private lazy var

假设你有一个简单的动画

    let e : CABasicAnimation = CABasicAnimation(keyPath: "strokeEnd")
    e.duration = 2.0
    e.fromValue = 0 
    e.toValue = 1.0
    e.repeatCount = .greatestFiniteMagnitude
    self.someLayer.add(e, forKey: nil)
一层的

private lazy var someLayer: CAShapeLayer
读取每个动画步骤的strokeEnd值非常容易

只需更改为自定义图层

private lazy var someLayer: CrazyLayer
然后

class CrazyLayer: CAShapeLayer {
    override func draw(in ctx: CGContext) {
        print("Yo \(presentation()!.strokeEnd)")
        super.draw(in: ctx)
    }
}
实际上,在每一步都可以设置图层的特性值,这将非常方便

例如:

class CrazyLayer: CAShapeLayer {
    override func draw(in ctx: CGContext) {
        print("Yo \(presentation()!.strokeEnd)")
        strokeStart = presentation()!.strokeEnd - 0.3
        super.draw(in: ctx)
    }
}
当然你不能那样做-

正在尝试修改只读层

也许您可以有一个自定义的可设置动画的属性

class LoopyLayer: CAShapeLayer {
    @NSManaged var trick: CGFloat

    override class func needsDisplay(forKey key: String) -> Bool {
        if key == "trick" { return true }
        return super.needsDisplay(forKey: key)
    }

    ... somehow for each frame
    strokeEnd = trick * something
    backgroundColor = alpha: trick
}
如何“手动”设置每个帧的可设置动画的属性值

是否有一种方法可以简单地提供(覆盖?)一个计算每帧值的函数?如何通过计算其他特性或其他自定义特性,在某些特性上设置每个帧的值

(脚注1-一个棘手的解决办法是滥用关键帧动画,但这并不是重点。)


(脚注2-当然,使用CADisplayLink以普通的手动方式制作动画通常更好,而不必担心动画,但本QA是关于动画的。)

粗略地说,
CoreAnimation
使您能够根据特定的计时功能在特定值之间执行插值

CAAnimation
具有在给定时间将其内插值应用于层的

draw(在ctx:CGContext中)
方法调用之前的
display
方法调用堆栈中,在模型层的类(
init(layer:)
调用)的实例中创建了表示层之后,会将该值注入表示层

因此,假设表示层的类与自定义层的类相同,一种解决方法是使动画特性不同于用于渲染层内容的特性。您可以设置
interpolatedValue
属性的动画,并具有另一个动态属性
strokeEnd
,该属性将在
interpolatedValue
值之外的每一帧上动态计算适当的值

在边缘情况下,
interpolatedValue
可能只是从0到1的动画进度,基于此,您可以动态计算表示层中的
strokeEnd
值。您甚至可以向学员询问给定进度的值:

@objc @NSManaged open dynamic var interpolatedValue: CGFloat

open override class func needsDisplay(forKey key: String) -> Bool {
    var result = super.needsDisplay(forKey: key)
    result = result || key == "interpolatedValue"
    return result
}

open var strokeEnd : CGFloat {
    get {
       return self.delegate.crazyLayer(self, strokeEndFor: self.interpolatedValue)
    }
    set {
        ...
    }
}

另一种解决方法是使用
CAKeyframeAnimation
,在其中可以指定在相应时间必须为可设置动画的属性指定的值


如果您可能希望在每一帧上指定插值组件中的一个复杂值,我有一个通过插值其属性为
NSAttributedString
值的动画指定的位置,以及我描述方法的位置。

您知道如何暂停动画吗?只要在这里搜索,你就能找到很多信息。嗨@E.Coms!我想你根本不明白这里要问什么。我知道你的意思,但你不能用公共API来做。所以这些方法是不安全的。谢谢,我认为你们的第3段是问题的核心,很好。但我。。。。。。。。。。。。。。。。。不知道怎么做:)例如,你说可以设置插值属性的动画,但我真的不知道在我们所说的内容的同一上下文中的柯德。(对不起!:)也许到时候你可以慷慨地添加更多的kode细节…:请参阅我的文章,这里我展示了如何创建可设置动画的层属性的示例。我会在这里添加一些代码。明白!行。好东西,一流的文章
let animation = CABasicAnimation(keyPath: "interpolatedValue")
animation.duration = 2.0
animation.fromValue = 0.0
animation.toValue = 1.0
crazyLayer.add(animation, forKey: "interpolatedValue")