Reputation: 5303
Using this code:
func rotateTheView(_ aView: UIView, inClockwiseDirection isClockwise: Bool) {
let multiplier = (isClockwise ? 1 : -1)
let key = (isClockwise ? "Spin" : "Rotate")
var rotation: CABasicAnimation?
rotation = CABasicAnimation(keyPath: "transform.rotation")
rotation!.fromValue = Int(0)
let multiplicand = multiplier * 2
rotation!.toValue = Int(Double(multiplicand) * .pi)
rotation!.duration = 30 // Speed
rotation!.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
rotation!.repeatCount = HUGE //HUGE_VALF Repeat forever.
aView.layer.add(rotation!, forKey: key)
}
I get the animation I want. (Either a wheel spins, or a cell rotates fast enough in the opposite direction to always remain exactly right side up).
However, when the 30 seconds (duration) is up, there is a flicker as the view jumps back to how it looked before the animation.
I understand it is supposed to work this way.
How do I apply the rotation to the "before" image so that when the duration expires I don't see any cells jump?
Increasing the duration of the animation slows the wheel's spin, so that is not an appropriate solution.
If #22521690 applies, I don't understand how - I do not have an explicit CATransaction.
Upvotes: 2
Views: 571
Reputation: 131398
On the next line after applying the animation to the layer, set the property you're animating to its ending value.
Because an animation is "in-flight", the normal display of the layer is covered the presentation layer, a special animation layer.
Once the animation is complete, the presentation layer is hidden/removed, and the actual layer is exposed. If it is a the same state as the presentation layer at the end of the animation then there's no jump.
That code might look like this:
func rotateTheView(_ aView: UIView, inClockwiseDirection isClockwise: Bool) {
let multiplier = (isClockwise ? 1 : -1)
let key = (isClockwise ? "Spin" : "Rotate")
var rotation: CABasicAnimation?
rotation = CABasicAnimation(keyPath: "transform.rotation")
rotation!.fromValue = 0.0
let multiplicand = multiplier * 2
let finalAngle = Double(multiplicand) * .pi
rotation!.toValue = finalAngle
rotation!.duration = 30 // Speed
rotation!.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
rotation!.repeatCount = HUGE //HUGE_VALF Repeat forever.
aView.layer.add(rotation!, forKey: key)
//-------------------
//Set the final transform on the layer to the final rotation,
//but without animation
CATransaction.begin()
CATransaction.setDisableActions(true)
let finalTransform = CATransform3DMakeRotation(CGFloat(finalAngle), 0.0, 0.0, 1.0)
aView.layer.transform = finalTransform
CATransaction.commit()
//-------------------
}
Upvotes: 2
Reputation: 4035
Try
rotation!.toValue = Double(multiplicand) * .pi
instead of
rotation!.toValue = Int(Double(multiplicand) * .pi)
The issue is with the radian precision which is lost due to Int conversion.
Upvotes: 2