The majority of the visual effects used throughout the iOS 5 user
interface on the iPad are performed using Core Animation. Core Animation
provides a simple mechanism for implementing basic animation within an
iPad application. If you need a user interface element to gently fade in
or out of view, slide smoothly across the screen or gracefully resize
or rotate before the user’s eyes, these effects can be achieved using
Core Animation in just a few lines of code.
In this chapter we will provide an overview of the basics of Core
Animation and work through a simple example. While much can be achieved
with Core Animation, however, it should be noted that if you plan to
develop a graphics intensive 3D style application then it is more likely
that OpenGL ES will need to be used, a subject area to which numerous
books are dedicated.
UIView Core Animation Blocks
The concept of Core Animation involves the implementation of
so-called animation blocks. Animation blocks are used to mark the
beginning and end of a sequence of changes to the appearance of a UIView
and its corresponding subviews. Once the end of the block is reached
the animation is committed and the changes are performed over a
specified duration. For the sake of example, consider a UIView object
that contains a UIButton connected to an outlet named theButton. The
application requires that the button gradually fade from view over a
period of 3 seconds. This can be achieved by making the button
transparent through the use of the alpha property:
theButton.alpha = 0;
Simply setting the alpha property to 0, however, causes the button to
immediately become transparent. In order to make it fade out of sight
gradually we need to place this line of code in an animation block. The
start of an animation block is represented by a call to the
beginAnimations class method of the UIView class:
[UIView beginAnimations:nil context:nil];
The end of the animation block triggers the animation sequence through a call to the commitAnimations method:
[UIView commitAnimations];
A variety of properties may also be defined within the animation
block. For example, the duration of the animation (in our hypothetical
example this needs to be 3 seconds) can be declared by a call to the
setAnimationDuration class method:
[UIView setAnimationDuration:3];
Bringing this all together gives us a code sequence to gradually fade out a button object over a period of 3 seconds:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:3];
theButton.alpha = 0;
[UIView commitAnimations];
Understanding Animation Curves
In addition to specifying the duration of an animation sequence, the
linearity of the animation timeline may also be defined by calling the
UIView setAnimationCurve class method. This setting controls whether the
animation is performed at a constant speed, whether it starts out slow
and speeds up and so on. There are currently four possible animation
curve settings:
- UIViewAnimationCurveLinear – The animation is performed at constant speed for the specified duration.
- UIViewAnimationCurveEaseOut – The animation starts out fast and slows as the end of the sequence approaches
- UIViewAnimationCurveEaseIn – The animation sequence starts out slow and speeds up as the end approaches.
- UIViewAnimationCurveEaseInOut – The animation starts slow, speeds up and then slows down again.
Receiving Notification of Animation Completion
Once an animation sequence has been committed and is underway it may
be necessary to receive notification when the animation is completed so
that the application code can, for example, trigger another animation
sequence. The UIView setAnimationDidStopSelector class method allows a
method to be specified that will be called when the animation sequence
is completed. For example, the following code fragment declares that the
method named animationFinished is to be called at the end of the
animation sequence:
[UIView setAnimationDidStopSelector:
@selector(animationFinished:finished:context:)];
The animationFinished method would subsequently be declared as follows:
-(void)animationFinished:(NSString *)animationID
finished:(NSNumber *)finished
context:(void *)context
{
// Code to be executed on completion of animation sequence
}
Performing Affine Transformations
Transformations allow changes to be made to the coordinate system of a
screen area. This essentially allows the programmer to rotate, resize
and translate a UIView object. A call is made to one of a number
transformation functions and the result assigned to the transform
property of the UIView object.
For example, to change the scale of a UIView object named myView by a factor of 2 in both height and width:
myView.transform = CGAffineTransformMakeScale(2, 2);
Similarly, the UIView object may be rotated using the
CGAffineTransformMakeRotation which takes as an argument the angle (in
radians) by which the view is to be rotated. The following code, for
example, rotates a view by 90 degrees:
myView.transform = CGAffineTransformMakeRotation( 90 * M_PI / 180);
The key point to keep in mind with transformations is that they
become animated effects when performed within an animation block. The
transformations evolve over the duration of the animation and follow the
specified animation curve in terms of timing.
Combining Transformations
Two transformations may be combined to create a single transformation
effect via a call to the CGAffineTransformConcat() function. This
function takes as arguments the two transformation objects that are to
be combined. The result may then be assigned to the transform property
of the UIView object to be transformed. The following code fragment, for
example, both scales and rotates a UIView object named myView:
CGAffineTransform scaleTrans =
CGAffineTransformMakeScale(2, 2);
CGAffineTransform rotateTrans =
CGAffineTransformMakeRotation(angle * M_PI / 180);
myView.transform = CGAffineTransformConcat(scaleTrans, rotateTrans);
Affine transformations offer an extremely powerful and flexible
mechanism for creating animations and it is just not possible to do
justice to these capabilities in a single chapter. In order to learn
more about affine transformations, a good starting place is the
Transforms chapter of Apple’s Quartz 2D Programming Guide.
Creating the Animation Example Application
The remainder of this chapter is dedicated to the creation of an iPad
application intended to demonstrate the use of Core Animation. The end
result is a simple application on which a blue square appears. When the
user touches a location on the screen the box moves to that location.
Through the use of affine transformations, the box will rotate 180
degrees as it moves to the new location whilst also changing in size.
Begin by launching Xcode and creating a new Single View Application with both product and class prefix named animate.
Implementing the Interface File
For the purposes of this application we will need a UIView to
represent the blue square and variables to contain the rotation angle
and scale factor by which the square will be transformed. These need to
be declared in the animateViewController.h file as follows:
#import <UIKit/UIKit.h>
@interface animateViewController : UIViewController
@property (nonatomic) float scaleFactor;
@property (nonatomic) float angle;
@property (strong, nonatomic) UIView *boxView;
@end
Drawing in the UIView
Having declared the UIView reference we now need to initialize an
instance object and draw a blue square located at a specific location on
the screen. We also need to initialize our scaleFactor and angle
variables and add boxView as a subview of the application’s main view
object. These tasks only need to be performed once when the application
first starts up so a good option is to override the loadView method in
the animateViewController.m file. Note that in addition to adding this
method we also need to synthesize access to the previously declared
properties:
#import "animateViewController.h"
@interface animateViewController ()
@end
@implementation animateViewController
@synthesize boxView, scaleFactor, angle;
.
.
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
[super loadView];
scaleFactor = 2;
angle = 180;
CGRect frameRect = CGRectMake(10, 10, 100, 100);
boxView = [[UIView alloc] initWithFrame:frameRect];
boxView.backgroundColor = [UIColor blueColor];
[self.view addSubview:boxView];
}
.
.
@end
Detecting Screen Touches and Performing the Animation
When the user touches the screen the blue box needs to move from its
current location to the location of the touch. During this motion, the
box will rotate 180 degrees and change in size. The detection of screen
touches was covered in detail in An Overview of iOS 5 iPad Multitouch,
Taps and Gestures. For the purposes of this example we want to initiate
the animation at the point that the user’s finger is lifted from the
screen so we need to implement the touchesEnded method in the
animateViewController.m file:
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.view];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:2];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
CGAffineTransform scaleTrans =
CGAffineTransformMakeScale(scaleFactor, scaleFactor);
CGAffineTransform rotateTrans =
CGAffineTransformMakeRotation(angle * M_PI / 180);
boxView.transform = CGAffineTransformConcat(scaleTrans, rotateTrans);
angle = (angle == 180 ? 360 : 180);
scaleFactor = (scaleFactor == 2 ? 1 : 2);
boxView.center = location;
[UIView commitAnimations];
}
Before compiling and running the application we need to take some
time to describe the actions performed in the above method. First, the
method gets the UITouch object from the touches argument and the
locationInView method of this object is called to identify the location
on the screen where the touch took place:
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.view];
The animation block is then started and the current class declared as
the delegate. The duration of the animation is set to 2 seconds and
curve set to ease in/ease out:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:2];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
Two transformations are then generated for the view, one to scale the
size of the view and one to rotate it 180 degrees. These
transformations are then combined into a single transformation and
applied to the UIView object:
CGAffineTransform scaleTrans =
CGAffineTransformMakeScale(scaleFactor, scaleFactor);
CGAffineTransform rotateTrans =
CGAffineTransformMakeRotation(angle * M_PI / 180);
boxView.transform = CGAffineTransformConcat(scaleTrans, rotateTrans);
Ternary operators are then used to switch the scale and rotation
angle variables ready for the next touch. In other words, after rotating
180 degrees on the first touch the view will need to be rotated to 360
degrees on the next animation. Similarly, once the box has been scaled
by a factor of 2 it needs to scale back to its original size on the next
animation:
angle = (angle == 180 ? 360 : 180);
scaleFactor = (scaleFactor == 2 ? 1 : 2);
Finally, the location of the view is moved to the point on the screen
where the touch occurred before the animation is committed:
boxView.center = location;
[UIView commitAnimations];
Once the touchesEnded method has been implemented it is time to try out the application.
Building and Running the Animation Application
Once the all the code changes have been made and saved, click on the
Run button in the Xcode toolbar. Once the application has compiled it
will load into the iOS Simulator (refer to
Testing iOS 5 Apps on the iPad – Developer Certificates and Provisioning Profiles for steps on how to run the application on an iPad device).
When the application loads the blue square should appear near the
top left hand corner of the screen. Click (or touch if running on a
device) the screen and watch the box glide and rotate to the new
location, the size of the box changing as it moves:
Figure 49-1
Summary
Core Animation provides an easy to implement interface to animation
within iOS 5 iPad applications. From the simplest of tasks such as
gracefully fading out a user interface element to basic animation and
transformations, Core Animation provides a variety of techniques for
enhancing user interfaces. This chapter covered the basics of Core
Animation before working step-by-step through an example to demonstrate
the implementation of motion, rotation and scaling animation.