NixiliaAK NixiliaAK - 4 months ago 43
Swift Question

Create a continuously rotating square on the screen using animateKeyframesWithDuration

I tried to use the code below to create a continuously rotating square on the screen. But I don't know why the rotational speed is changing. How could I change the code to make the rotational speed invariable? I tried different

UIViewKeyframeAnimationOptions
, but seems none of them work.

override func viewDidLoad() {
super.viewDidLoad()

let square = UIView()
square.frame = CGRect(x: 55, y: 300, width: 40, height: 40)
square.backgroundColor = UIColor.redColor()
self.view.addSubview(square)

let duration = 1.0
let delay = 0.0
let options = UIViewKeyframeAnimationOptions.Repeat
UIView.animateKeyframesWithDuration(duration, delay: delay, options: options, animations: {
let fullRotation = CGFloat(M_PI * 2)

UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 1/3, animations: {
square.transform = CGAffineTransformMakeRotation(1/3 * fullRotation)
})
UIView.addKeyframeWithRelativeStartTime(1/3, relativeDuration: 1/3, animations: {
square.transform = CGAffineTransformMakeRotation(2/3 * fullRotation)
})
UIView.addKeyframeWithRelativeStartTime(2/3, relativeDuration: 1/3, animations: {
square.transform = CGAffineTransformMakeRotation(3/3 * fullRotation)
})
}, completion: {finished in
})
}

Answer

That's really odd... UIView.animateKeyframesWithDuration isn't working as I would expect it to with UIViewKeyframeAnimationOptions.CalculationModeLinear|UIViewKeyframeAnimationOpti‌​ons.Repeat passed in with options.

If you use the non-block method of creating a keyframe animation (see below) the rotation repeats as expected.

If I find out why the block-based option isn't working I'll try and remember to update answer here too!

override func viewDidLoad() {
    super.viewDidLoad()


    let square = UIView()
    square.frame = CGRect(x: 55, y: 300, width: 40, height: 40)
    square.backgroundColor = UIColor.redColor()
    self.view.addSubview(square)

    let fullRotation = CGFloat(M_PI * 2)

    let animation = CAKeyframeAnimation()
    animation.keyPath = "transform.rotation.z"
    animation.duration = 2
    animation.removedOnCompletion = false
    animation.fillMode = kCAFillModeForwards
    animation.repeatCount = Float.infinity
    animation.values = [fullRotation/4, fullRotation/2, fullRotation*3/4, fullRotation]

    square.layer.addAnimation(animation, forKey: "rotate")

}