Create a continuously rotating square on the screen using animateKeyframesWithDuration

心已入冬 提交于 2019-12-22 04:37:25

问题


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

回答1:


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

}



回答2:


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.




回答3:


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.




回答4:


AFAIU, this is happening because the default animation curve is UIViewAnimationOption.CurveEaseInOut.

Unfortunately, UIViewKeyframeAnimationOptions doesn't have options for changing the curve, but you can add them manually!

Use this extension:

Swift 2

extension UIViewKeyframeAnimationOptions {
    static var CurveEaseInOut: UIViewKeyframeAnimationOptions { return UIViewKeyframeAnimationOptions(rawValue: UIViewAnimationOptions.CurveEaseInOut.rawValue) }
    static var CurveEaseIn: UIViewKeyframeAnimationOptions { return UIViewKeyframeAnimationOptions(rawValue: UIViewAnimationOptions.CurveEaseIn.rawValue) }
    static var CurveEaseOut: UIViewKeyframeAnimationOptions { return UIViewKeyframeAnimationOptions(rawValue: UIViewAnimationOptions.CurveEaseOut.rawValue) }
    static var CurveLinear: UIViewKeyframeAnimationOptions { return UIViewKeyframeAnimationOptions(rawValue: UIViewAnimationOptions.CurveLinear.rawValue) }
}

Swift 3, 4, 5

extension UIView.KeyframeAnimationOptions {
    static var curveEaseInOut: UIView.KeyframeAnimationOptions { return UIView.KeyframeAnimationOptions(rawValue: UIView.AnimationOptions.curveEaseInOut.rawValue) }
    static var curveEaseIn: UIView.KeyframeAnimationOptions { return UIView.KeyframeAnimationOptions(rawValue: UIView.AnimationOptions.curveEaseIn.rawValue) }
    static var curveEaseOut: UIView.KeyframeAnimationOptions { return UIView.KeyframeAnimationOptions(rawValue: UIView.AnimationOptions.curveEaseOut.rawValue) }
    static var curveLinear: UIView.KeyframeAnimationOptions { return UIView.KeyframeAnimationOptions(rawValue: UIView.AnimationOptions.curveLinear.rawValue) }
}

Now you can use curve options in UIView.animateKeyframesWithDuration method

Swift 2

let keyframeOptions: UIViewKeyframeAnimationOptions = [.Repeat, .CurveLinear]
UIView.animateKeyframesWithDuration(duration, delay: delay, options: keyframeOptions, animations: {
    // add key frames here
}, completion: nil)

Swift 3, 4, 5

let keyframeOptions: UIView.KeyframeAnimationOptions = [.repeat, .curveLinear]
UIView.animateKeyframes(withDuration: duration, delay: delay, options: keyframeOptions, animations: {
    // add key frames here
}, completion: nil)


来源:https://stackoverflow.com/questions/26665124/create-a-continuously-rotating-square-on-the-screen-using-animatekeyframeswithdu

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!