0

I have defined a CAKeyframeAnimation to rotate a CALayer along z axis. For the animation to work, I've used the values, keyTimes and duration properties of the animation object.

Below is what I've:

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")

Now I need to perform some other tasks when the layer rotates to every x degrees. I can't find a way for my cause.

What do I need to do to be notified of every x degrees change in the rotation?


I've tried KVO for value observation like:

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

The observation block never gets triggered.


Also tried similar approach answered in this question. But seems that the solutions provided there only work for "progress" key not for "transform.rotation.z" (also tried with "transform" / "transform.rotation" key names but they don't also work. Even "transform" emits values for progress ranging 0.0 ~ 1.0).

None of the above tries seem to work.

nayem
  • 7,285
  • 1
  • 33
  • 51

1 Answers1

0

I think there can be one approach is using Timer. KVO is not available for these properties.

You can start the timer with the animation begin and continuously check for the status of the degree of rotation. Below is the code -

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()
Shashank Mishra
  • 1,051
  • 7
  • 18
  • Well, in reality, the rotation will be much faster than that I've showed in the example. It may have been 10~20 rotations per second or so. Therefore, I think using `Timer` isn't a good idea here. Also because there are other concerns around using `Timer` for these animation observation. The comment section [in this answer](https://stackoverflow.com/a/1558083/3687801) points to that. – nayem Jul 09 '20 at 14:39
  • And even if I choose to use your approach for now, I don't see any luck for **continuously check for the status of the degree of rotation** you mentioned as the `animation.values` in the timer event handler method always gives the values set initially at the time of `CAKeyFrameAnimation` object creation. – nayem Jul 09 '20 at 14:42
  • Then, you can try something like this https://stackoverflow.com/questions/18827973/core-animation-progress-callback – Shashank Mishra Jul 10 '20 at 04:34
  • Yes, I had already tried that before posting this question. But no luck. Seems, that works for **"progress"** only but not for **"transform.rotation.z"**. Even interesting thing is that if I use "transform" (not transform.rotation.z though) key in the subclass of `CALayer`, I get the values for "progress" (ranging 0.0 ~ 1.0). – nayem Jul 10 '20 at 16:12