假设您有一个简单的动画

    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以普通的旧手动方式进行动画处理,而不用担心CAAnimation,但是此QA与CAAnimation有关。)

最佳答案

粗略地说,CoreAnimation使您能够根据某个计时功能在某些值之间执行插值。
CAAnimation具有private method,它在给定时间将其插值应用于图层。

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

因此,假设表示层的类与自定义层的类相同,一种解决方法是使动画属性不同于用于呈现层内容的属性。您可以设置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 {
        ...
    }
}
let animation = CABasicAnimation(keyPath: "interpolatedValue")
animation.duration = 2.0
animation.fromValue = 0.0
animation.toValue = 1.0
crazyLayer.add(animation, forKey: "interpolatedValue")

解决该问题的另一种方法是使用CAKeyframeAnimation,您可以在其中指定必须在相应的时间将哪个值分配给animable属性。

如果您可能想在每个帧中从插值分量中分配一个复杂的值,我有一个project,其中通过对属性值进行插值来为NSAttributedString值动画制作,并在article中描述了方法。

关于ios - 在CAAnimation期间修改值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57699815/

10-11 04:28