I wrote the following little demo that rotates a UIView 360° by rotating it 90° at a time. That means the animation has 4 steps
I wanted it to ease in on the first animation step, go at a steady pace for the middle 2 steps, and then use ease out timing for the last step so it coasts to a stop. The code is below. Here is the animation timing it uses:
Animating to 90°, options = curveEaseIn
Animating to 180°, options = curveLinear
Animating to 270°, options = curveLinear
Animating to 0°, options = curveEaseOut
Each step takes 1/2 second, for a total duration of 2 seconds. However, since the first and last steps take 1/2 second but start/end at a slower pace, the "full speed" part of those animation steps is noticeably faster than the middle 2 animation steps that use linear timing. The animation is not smooth as a result.
Is there an easy way to adjust the step timing so each of the steps in the animation runs at the same pace as the beginning/end step that has ease in/ease out timing?
I guess I could instead create a keyframe animation where the entire animation uses ease-in/ease-out timing, and the intermediate steps inside the animation use linear timing. It seems like there should be an easy way to get that out of step-wise animation however.
class ViewController: UIViewController {
var rotation: CGFloat = 0
@IBOutlet weak var rotateableView: RotatableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBAction func handleRotateButton(_ sender: UIButton? = nil) {
let duration = 0.5
var optionsValue: (options: UIView.AnimationOptions, optionsName: String) = (.curveLinear, "curveLinear")
self.rotation = fmod(self.rotation + 90, 360)
sender?.isEnabled = false
if self.rotation == 0 {
optionsValue = (.curveEaseOut, "curveEaseOut") // Ending the animatino, so ease out.
} else if self.rotation == 90 {
optionsValue = (.curveEaseIn, "curveEaseIn") // Beginning the animation, so ease in
}
let rotation = String(format:"%3.0f", self.rotation)
print("Animating to \(rotation)°, options = \(optionsValue.optionsName)")
UIView.animate(withDuration: duration, delay: 0, options: optionsValue.options) {
let angle = self.rotation / 180.0 * CGFloat.pi
self.rotateableView.transform = CGAffineTransform.init(rotationAngle: angle)
} completion: { finished in
if self.rotation != 0 {
self.handleRotateButton(sender)
} else {
self.rotation = 0
sender?.isEnabled = true
}
}
}
}