Animations and transformations

April 26th, 2009 by Chris Leave a reply »

Using right animation / transformation can improve quality of your application. There are most important during game development.

You can use 3 basic transformations – you can marge them or invent your own. These 3 animations are:

  • rotation
  • scale
  • translation

animationsimulator

You can apply animation to almost everything – images (UIImageView), buttons (UIButton), toolbars, label, views…

Rotation:

Let’s say you have an image (UIImageView *myImage) and you would like to do something with it. To rotate it:

myImage.transform = CGAffineTransformMakeRotation(M_PI*0.25);

This will rotate image by 45 degrees right. Here are the typical values and their degree equivalents:

  • M_PI * 0.00 = 0° (original condition)
  • M_PI * 0.25 = 45°
  • M_PI * 0.50 = 90°
  • M_PI * 0.75 = 135°
  • M_PI * 1.00 = 180°
  • M_PI * -0.75 = 225°
  • M_PI * -0.50 = 270°
  • M_PI * -0.25 = 315°

If you would like to use degrees not the range <-1 ; 1> multiplied by M_PI you can define the constant value in header of your class: #define radianConst M_PI/180.0 (right under the #import lines). Now if you want to turn your image by 63 degrees use this:

myImage.transform = CGAffineTransformMakeRotation(63.0*radianConst);

Scale

Scale allows you to zoom in / zoom out your image. It’s more than simple scale, you can set the scale parameter different for image’s width and height. If you would like to have the image 2 times wider and 1.5 times higher try this:

myImage.transform = CGAffineTransformMakeScale(2.0,1.5);

Don’t be surprised that after this operation your image will be pixeled, that’s why in future you should provide images in higher resolution make them smaller on load (for example CGAffineTransformMakeScale(0.5,0.5)) and later when needed show them in original dimensions using CGAffineTransformMakeScale(1.0,1.0).

Scale gives you one more cool effect. If you set scale parameter as a negative value your image will be scaled and flipped horizontally or vertically. Examples:

  • CGAffineTransformMakeScale(-1.0,2.0)image flipped horizontally and twice higher
  • CGAffineTransformMakeScale(1.5,-3.0) – image 1.5 times wider, 3 times higher and flipped vertically
  • CGAffineTransformMakeScale(-2.0,-2.0)image 2 times bigger and flipped both horizontally and vertically

Translation

Translation is doing almost the same thing as changing the center value of any object. It moves image along X and Y axises. It’s the poorest so I will give you only 1 example and won’t talk about this any more.

  • CGAffineTransformMakeTranslation(50.0,20.0)image moved 50 pixels to the right and 20 to the botton

Similar effect you will get using center as I mentioned before: myImage.center = CGPointMake(140.0,90.0). Both of them has their own advantages and disadvantages, but let’s now move to something more interesting.

Animations

You know how to rotate an image (or anything else) by given degree, scale, flip, or move. How about creating a smooth animation? Well it’s very simple:

	[UIView beginAnimations:nil context:NULL];
	[UIView setAnimationDuration:1.5];
	// other animations goes here
	myImage.transform = CGAffineTransformMakeRotation(M_PI*0.5);
	// other animations goes here
	[UIView commitAnimations];

This code will smoothly rotate your object by 45 degress during 1.5 seconds. Please note, that while performing any animation the application continue to run next tasks – doesn’t hold for a given amount of seconds. If you would like your app to do an action when the animation is finished you can use either the NSTimer:

[NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(nextMethodName) userInfo:nil repeats:NO];

or extend your animation code by it’s delegate and selector:

	[UIView beginAnimations:nil context:NULL];
	[UIView setAnimationDuration:1.5];
	[UIView setAnimationDelegate:self];
	[UIView setAnimationDidStopSelector:@selector(nextMethodName)];
	myImage.transform = CGAffineTransformMakeRotation(M_PI*0.5);
	// other animations goes here
	[UIView commitAnimations];

Remember that second example is much more efficient, but in that case, nextMethodName (whatever you name it) must return a boolean YES – not void which doesn’t return any value at all. Example:

-(BOOL)nextMethodName {
 	// some tasks
	return YES;
}

Animations can be great to have transitions between two views but I will talk about them in other article.

Two transformations at once

Using any of above transformations you are modyfing only one property – transform of a given object. For example the code:

myImage.transform = CGAffineTransformMakeScale(2.0,1.5);
myImage.transform = CGAffineTransformMakeRotation(M_PI*1.0);

will give you the image rotated by 180 degrees, but won’t be scaled – scale was canceled after making rotation.

If you would like to merge two transform use the following code:

animateLabel.transform = CGAffineTransformConcat(CGAffineTransformMakeScale(2.0, 1.5), CGAffineTransformMakeRotation(M_PI*1.0));

I personally really don’t like this. I didn’t enjoy matrices during Mathematics in school. Any transform creates the matrix and CGAffineTransformConcat is multiplying two matrices – the order is necessary. If you wanted to merge three transforms you would have to use CGAffineTransformConcat merging two transforms as an argument of another CGAffineTransformConcat mergin previous merge with next transform. Sound difficult? Yes, for me two.

Original shape

To conclude, if you would like to quickly cancel any transforms use CGAffineTransformIdentity as a transform property of any object.

myImage.transform = CGAffineTransformIdentity;

I guess it’s all you need to know about transforms and animations right now. Below you can download my project where you can rotate, scale, translate any object using sliders and watch the smooth scale animation.

xcodeproj

Download the project

Advertisement

19 comments

  1. Wally says:

    Excellent tutorial thanks! Question (newbie!), I’m wanting to take a given image that is on the screen at a specific spot, and “grow” it by a specific size/scale to make it appear to enlarge. The image however may be located at one edge of the screen, and the desire would be to make it grow towards the middle of the screen, ultimately ending-up at a specific coordinate. So would it need to transform the scale as well as the translation to move the x/y coordinates at the same time as “growing” the scale? Is there a way to do this in the way I described by wanting the final placement to be at a specific x/y spot?

  2. skram says:

    I use this macro instead, for Rotation:

    #define degreesToRadians(x) (M_PI * x / 180.0)

    Changing:
    myImage.transform = CGAffineTransformMakeRotation(63.0*radianConst);

    To This:
    myImage.transform = CGAffineTransformMakeRotation(degreesToRadians(63));

    Sam thing essentially. Just cleaner and quicker if using more than once.

  3. porn watch says:

    teen porn watch gg

  4. best blender says:

    I do not even know how I finished up here, but I believed this submit was once good. I do not realize who you are however definitely you’re going to a famous blogger in case you aren’t already. Cheers!

  5. Nick says:

    I simply had to appreciate you all over again. I am not sure the things that I might have sorted out without those opinions revealed by you directly on my situation. Completely was the intimidating dilemma in my circumstances, however , noticing your expert fashion you treated it took me to weep over gladness. I am thankful for your assistance as well as have high hopes you recognize what a great job you are accomplishing instructing others with the aid of your blog post. Most likely you haven’t come across any of us. http://www.handbagsdreams.com

  6. Tuyen Nguyen says:

    This should have been the first result in Google search with search terms “iphone objective c animation”.

    Great tutorial,

    Thank you very much.

  7. Neelam says:

    Its really use ful for me thanks for share it

  8. Adrian says:

    Great tutorial. I really needed that. Thank u!

  9. Dans_Edu says:

    Hello, I would like make a button like a dial blender , with 4 positions and this button rotate between 180º, how can i do that ?

    Thanks for help me

  10. Gabby says:

    Thanks for sharing. Always good to find a real exrept.

  11. Yoon Lee says:

    Awesome detail tutorial. I was struggled with using multiple uiviews with horizontal flip animation but this way worked fine for me.

  12. Zahur says:

    Hi,
    Nice tutorial thanks , it is really helpful for starters….
    Well I’m bit confuse that how can I provide the animation of Guillotine Blade drop animation. As blade dropping speed increases as it drops… So I tried doing by dividing the dropping animation into different small parts but it looks to jerky.. Basically i need to decrease the time of the animation in linear way so it results in smooth dropping of blade without any jerk…. Please guide me…
    Thanks & Regards,
    Zahur

  13. Shakayb says:

    Basically this is my code which draws a circle with 4 different colored and equal sized quadrants.What I want to do is to rotate this circle clockwise and anticlockwise i.e. clockwise’ when i touch circle and drag it a bit in clockwise direction and vice versa. I have made circle through core graphics.One more thing is that the circle must rotate initially at high speed and will slow down gradually until it stops.Any help in this regard will be greatly appreciated. Please reply ASAP.

    - (void)drawRect:(CGRect)rect {

    CGContextRef context = UIGraphicsGetCurrentContext();
    // CGRect mainSquare = self.bounds/2;

    CGRect mainSquare = CGRectMake(X_SPACE, Y_SPACE, 220, 200);

    CGContextSaveGState(context);

    // Create circle path and clip

    CGContextAddEllipseInRect(context, mainSquare);
    CGContextClip(context);

    // Define rects
    NSLog(@”helll %f”,mainSquare.size.width);
    CGRect topLeft = CGRectMake(mainSquare.origin.x, mainSquare.origin.y, (mainSquare.size.width / 2) , (mainSquare.size.height / 2) );
    CGRect topRight = CGRectMake((mainSquare.size.width / 2) + X_SPACE, mainSquare.origin.y, mainSquare.size.width / 2, (mainSquare.size.height / 2) );
    CGRect bottomLeft = CGRectMake(mainSquare.origin.x, (mainSquare.size.height / 2) + Y_SPACE, mainSquare.size.width / 2, (mainSquare.size.height / 2) );
    CGRect bottomRight = CGRectMake((mainSquare.size.width / 2) + X_SPACE, (mainSquare.size.height / 2) + Y_SPACE, mainSquare.size.width / 2, mainSquare.size.height / 2);
    // Define colors
    CGColorRef topLeftColor = [[UIColor redColor] CGColor];
    CGColorRef topRightColor = [[UIColor blueColor] CGColor];
    CGColorRef bottomLeftColor = [[UIColor greenColor] CGColor];
    CGColorRef bottomRightColor = [[UIColor yellowColor] CGColor];
    // Fill rects with colors
    CGContextSetFillColorWithColor(context, topLeftColor);
    CGContextFillRect(context, topLeft);
    CGContextSetFillColorWithColor(context, topRightColor);
    CGContextFillRect(context, topRight);
    CGContextSetFillColorWithColor(context, bottomLeftColor);
    CGContextFillRect(context, bottomLeft);
    CGContextSetFillColorWithColor(context, bottomRightColor);
    CGContextFillRect(context, bottomRight);
    CGContextRestoreGState(context);
    }

  14. Ryan says:

    Great tutorial – thank you…one question though – how do I rotate the image (animate clockwise/counterclockwise) on “touch down” instead of the slider?

    Thanks

    Ryan

  15. Justas says:

    All looks great, but I can’t find how to make it In/Out. What code do I need to add if I want that on first button press it would go smaller and on second press would get back to it’s previous size?
    Thanks.

    • Chris says:

      Can’t you just add a simple bool variable in header that will be true if the button has original dimensions and false if it’s scaled for example, and once button is being pressed you check the variable and make a little bit different action for both cases:

      -(IBAction)buttonPressed {
      [UIView beginAnimations:nil context:NULL];
      [UIView setAnimationDuration:1.5];
      if (buttonScaled) {
      myButton.transform = CGAffineTransformMakeScale(1.0,1.0);
      }
      else {
      myButton.transform = CGAffineTransformMakeScale(0.5,0.5);
      }
      buttonScaled = !buttonScaled;
      [UIView commitAnimations];
      }
      }

      hmm?

Leave a Reply