如何使用 CAKeyframeAnimation 变换旋转检测某些旋转进度?

Posted

技术标签:

【中文标题】如何使用 CAKeyframeAnimation 变换旋转检测某些旋转进度?【英文标题】:How to detect certain rotation progress with CAKeyframeAnimation transform rotation? 【发布时间】:2020-07-09 11:57:35 【问题描述】:

我定义了一个CAKeyframeAnimation 来沿z 轴旋转一个CALayer。为了使动画正常工作,我使用了动画对象的valueskeyTimesduration 属性。

以下是我的:

let rotationInDegrees: CGFloat = 7 * 360.0 // 7 times full rotation

let transformationAnimation = CAKeyframeAnimation(keyPath: "transform.rotation.z")
transformationAnimation.values = [0, rotationInDegrees * (CGFloat.pi / 180)]
transformationAnimation.keyTimes = [0, 1]
transformationAnimation.duration = 15

myLayer.add(transformationAnimation, forKey:"transformationAnimation")

现在我需要在图层旋转到每x 度时执行一些其他任务。我找不到我的事业的方法。

我需要做什么才能在旋转中的每个x 度变化时收到通知?


我尝试过使用 KVO 进行价值观察,例如:

token = transformationAnimation.observe(\.values)  (anim, values) in
    print(anim.values)

观察块永远不会被触发。


也尝试过类似的方法回答in this question。但似乎那里提供的解决方案只适用于"progress" 键而不适用于"transform.rotation.z"(也尝试使用"transform" / "transform.rotation" 键名,但它们也不起作用。即使"transform" 发出0.0 范围内的进度值~ 1.0)。

上述尝试似乎都不起作用。

【问题讨论】:

【参考方案1】:

我认为可以有一种方法是使用 Timer。 KVO 不适用于这些属性。

您可以在动画开始时启动计时器并不断检查旋转度数的状态。下面是代码-

import PlaygroundSupport
import UIKit

class Animation: NSObject, CAAnimationDelegate 
    
    var timer: Timer?
    
    func doAnimation() 
        let view = UIView.init(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
        view.backgroundColor = UIColor.red
        
        let rotationInDegrees: CGFloat = 7 * 360.0 // 7 times full rotation
        
        let transformationAnimation = CAKeyframeAnimation(keyPath: "transform.rotation.z")
        transformationAnimation.values = [0, rotationInDegrees * (CGFloat.pi / 180)]
        transformationAnimation.keyTimes = [0, 1]
        transformationAnimation.duration = 15
        transformationAnimation.delegate = self
        
        timer = Timer.scheduledTimer(timeInterval: 1.0,
              target: self,
              selector: #selector(eventWith(timer:)),
              userInfo: [ "animation" : transformationAnimation],
              repeats: true)
        
        view.layer.add(transformationAnimation, forKey:"transformationAnimation")
        
        PlaygroundPage.current.needsIndefiniteExecution = true
        PlaygroundPage.current.liveView = view
    
    
    func animationDidStart(_ anim: CAAnimation) 
        timer?.fire()
    
    
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) 
        timer?.invalidate()
        timer = nil
    
    
    // Timer expects @objc selector
    @objc func eventWith(timer: Timer!) 
        if let animation = timer.userInfo as? [String: CAAnimation] 
            print(animation.values)
        
    


let ballAnimation = Animation()
ballAnimation.doAnimation()

【讨论】:

嗯,实际上,旋转会比我在示例中显示的要快得多。它可能是每秒 10~20 转左右。因此,我认为在这里使用Timer 不是一个好主意。还因为使用Timer 进行这些动画观察还有其他问题。评论部分in this answer 指出了这一点。 即使我现在选择使用你的方法,我也看不出有任何运气不断检查旋转度的状态你提到的@定时器事件处理方法中的 987654326@ 总是给出在 CAKeyFrameAnimation 对象创建时最初设置的值。 然后,你可以试试这样的***.com/questions/18827973/… 是的,在发布这个问题之前我已经尝试过了。但没有运气。似乎,这仅适用于 "progress",但不适用于 "transform.rotation.z"。甚至有趣的是,如果我在 CALayer 的子类中使用“transform”(虽然不是 transform.rotation.z)键,我会得到“progress”的值(范围 0.0 ~ 1.0)。

以上是关于如何使用 CAKeyframeAnimation 变换旋转检测某些旋转进度?的主要内容,如果未能解决你的问题,请参考以下文章

CAKeyframeAnimation 完成时如何指定选择器?

如何在 Iphone 中停止 CAKeyFrameAnimation

如何同步几个不同图层的 CAKeyframeAnimation 动画?

如何获取CAKeyframeAnimation对象的当前屏幕xy位置?

iOS - CAKeyFrameAnimation - 未播放

为啥我不能使用 CAKeyframeAnimation 在 eulerAngle 上为 SCNnode 设置动画