简体   繁体   中英

iOS Swift - How to do 360 degree flip animation using CABasicAnimation and CATransform3DRotate with "m34" transform?

Despite all my best efforts, I can't figure out how to do a full cycle rotation animation of a UIView using CATransform3DRotate from left to right. Kindly note that I can already rotate it 360 degree with CABasicAnimation, but without CATransform3DRotate. However, I want to use .m34 transform for perspective depth. Solutions involving UIView.animate/transitions are not helpful in what I am trying to accomplish. Any help is much appreciated.

Edit: I searched far and wide in Stackoverflow and other places, but didn't find anything that describes how to do 360 rotation with CATransform3DRotate. Calling top guns out there for help as this is a question that does not seem to have been answered before. Thanks!

Here is the code that rotates UIView 180 degree.

var transform = CATransform3DIdentity
transform.m34 = 1.0 / -200.0

let animation = CABasicAnimation(keyPath: "transform")
animation.toValue = CATransform3DRotate(transform, CGFloat( Double.pi), 0, 1, 0)
animation.duration = 0.8
animation.beginTime = 0.0
animation.fillMode = .forwards
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
cardView.layer.add(animation, forKey: "360flip")

在此处输入图像描述

Added two lines before your last cardView.layer.add(animation…) line:

    animation.isCumulative = true
    animation.repeatCount = 2

Don't ask how long it took me to figure this out… It's 2am here now, so that'll give you a clue;)

Cheers.

PS Note - because you're repeating the animation you can't use .easeInEaseOut or you'll get a pause at 180º so you'll see I also changed that to linear.

Your current code is replacing the entire transform of the animating layer, meaning you can't apply the perspective transform to it. You also have issues with the end state being mathematically identical to the beginning state, and to cope with this you're trying to chain animations together, and using fill modes, which makes the whole thing more complicated.

First, let's deal with the transform. To get the perspective you want to set the .m34 of the layer's transform, which you're already doing:

var perspective = CATransform3DIdentity
perspective.m34 = 1 / -200
cardView.layer.transform = perspective

Next, to only touch the rotation of the layer's transform, you can use a more precise key path than transform :

let rotate = CABasicAnimation(keyPath: "transform.rotation.y")
rotate.fromValue = 0

This will leave the rest of the layer's transform intact.

Finally, how to force the animation engine to notice a difference when the end of the animation is identical to the start? Use byValue :

rotate.byValue = CGFloat.pi * 2

This forces the layer to take the long way round to 360 degrees, instead of the lazy shortcut of staying exactly where it is.

The final, complete code is:

var perspective = CATransform3DIdentity
perspective.m34 = 1 / -200
cardView.layer.transform = perspective
let rotate = CABasicAnimation(keyPath: "transform.rotation.y")
rotate.fromValue = 0
rotate.byValue = CGFloat.pi * 2
rotate.duration = 2
cardView.layer.add(rotate, forKey: nil)

Giving this result:

带透视的 360 度旋转标签

In short, you need two sets of animations.

Checkout my previous answer https://stackoverflow.com/a/24990978/945906

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM