6

I'm using CGAffineTransformMakeRotation to rotate a UIView inside an animation block, and I want to rotate it counterclockwise for 180ΒΊ.

However when I put

myView.animateWithDuration(0.5)
myView.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI))

it still rotates clockwise. What's confusing me is that if I write "manually" the value of M_PI, it works as expected

 // this will rotate counterclockwise
 myView.transform = CGAffineTransformMakeRotation(CGFloat(-3.14159265358979))

Why this behavior?

Edit: added I'm using an animation block

gpbl
  • 4,721
  • 5
  • 31
  • 45
  • i cannot reproduce your issue in objective-c or swift, always rotates clockwise - rotating by -3.141592 gives the desired effect. – luk2302 Jun 23 '15 at 15:52

2 Answers2

11

As I stated in my first comment and as Segii already wrote: the animation will take the shortest distance between where it's value is at now and where it is trying to go. The best solution imho is to use CABasicAnimation for forcing a counterclockwise rotation:

let anim = CABasicAnimation(keyPath: "transform.rotation")
anim.fromValue = M_PI
anim.toValue = 0
anim.additive = true
anim.duration = 2.0

myView.layer.addAnimation(anim, forKey: "rotate")
myView.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI))

This will rotate it by 180 counter clockwise in one go.

The angle you specify in the last line + the fromValue is the starting angle -> 0. And then the rotation will go the distance (toValue - fromValue) = 0 - M_PI = - M_PI -> counter clockwise 180 degree rotation.

luk2302
  • 55,258
  • 23
  • 97
  • 137
  • this doesn't work for me for some reason. also I'm using `CGFloat.pi` as this preferred with swift 3.0 – NoSixties Apr 03 '17 at 08:41
  • M_PI and -M_PI didn't work for me, however subtracting/adding 0.01 from/to the CGAffineTransformMakeRotation values can create that shortest distance for the animation to take, but visually you won't see a difference. – Repose Nov 07 '18 at 19:01
5

As I understood, you're trying to rotate view within animation block. animateWithDuration will always perform animation with the shortest way. So, M_PI and -M_PI gives the same destination position. The reason, why you get expected animation direction when setting it manually is that your manual value is really smaller that M_PI, so the shortest way to rotate is counterclockwise.

To get expected behaviour, you'll have to chain at least two animations, splitting you rotation angle. For example

//first animation block
myView.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI/2))CGAffineTransformMakeRotation;
//second animation block
myView.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI/2))CGAffineTransformMakeRotation;

Swift 3.0

myView.transform = CGAffineTransform(rotationAngle: CGFloat(-M_PI/2))

Or, much more reliable, use CAKeyframeAnimation

Maxwell
  • 6,532
  • 4
  • 37
  • 55
Sergii Martynenko Jr
  • 1,407
  • 1
  • 9
  • 18