Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
        })
    }         
like image 282
NixiliaAK Avatar asked Oct 30 '14 23:10

NixiliaAK


3 Answers

I faced same problem before, this is how I make it work:

Swift 2

let raw = UIViewKeyframeAnimationOptions.Repeat.rawValue | UIViewAnimationOptions.CurveLinear.rawValue
let options = UIViewKeyframeAnimationOptions(rawValue: raw)

Swift 3,4,5

let raw = UIView.KeyframeAnimationOptions.repeat.rawValue | UIView.AnimationOptions.curveLinear.rawValue
let options = UIView.KeyframeAnimationOptions(rawValue: raw)

I figured this problem out just before gave it up. I don't think there is doc about it, but it just work.

like image 147
Alan Zhang Avatar answered Oct 21 '22 01:10

Alan Zhang


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

}
like image 37
MathewS Avatar answered Oct 20 '22 23:10

MathewS


Add UIViewKeyframeAnimationOptionCalculationModeLinear do your keyframe options. The default behavior for UIView animations is to "ease in/out" of the animation. i.e., start slow, go up to speed, then slow down again just near the end.

like image 1
Daniel T. Avatar answered Oct 21 '22 00:10

Daniel T.