Xcode Animations and Transitions


Ever wanted to be able to use fancy transitions and animations in your Xcode applications? This series provides the method and the means to implement terrific flips and ripples throughout your app, showing window transition effects using undocumented and documented Objective-C code that can be implemented anywhere quickly and efficiently.

The Static Preview

Some of the more simple animations that we’ll be starting to get into in later parts of this series.

Anim CubeAnim FlashAnim CurlAnim Cube No Back

A little more animated

Pardon the pun. The following are some more examples of animation in both undocumented and documented code. (Quicktime is required to view these video previews). In this series of tutorials, we’ll be making projects similar to these. (Eventually. This first part, as I mentioned, is an introduction. The next few sections consolidate on this and get increasingly more spectacular, which is to be expected of course.)

CoreGraphics

The Cube Animation Demo using CGSPrivate.h was made in forty lines of written code. The actual application moves back and forth between the tabs, and closes with a nifty animation upon reaching the end of the tabs. After reading this tutorial, you should be able to write a similar app.

Cube Animation Demo

CoreImage

Made using 100% documented CoreImage filters, the CoreImage Animation Demo was written in a little over 60 lines of code. You’ll notice animations like the ripple effect that you get on the Dashboard are able to be implemented using completely documented code. There are also exploding effects, page flip effects and a laser effect! This method is absolutely stunning, but requires more code than the CoreGraphics method. We’ll be visiting CoreImage in the next part of the tutorial.

CoreImage Animation Demo (3.1 MB)

That’s the preview, now let’s get coding!




Animations and Transitions using CoreGraphics

Introducing CGSPrivate.h

Richard J Wareham wrote up an excellent header file for “undocumented CoreGraphics stuff”, and this “Core Graphics” header file (View) will be the basis for all our animations in this first part of the tutorial.

Download the CGSPrivate Header File

If you do a search for any of these functions in Google or anywhere else, chances are you’ll come up with few, if any results. The reason for this is that CGSPrivate.h is exclusively an internal API for Apple. Regardless, you will see many implementations of this in the Mac environment, with the cube effect during Fast User Switching being quite popular. The header file includes functions for creating, running and discarding animations, which means that there is relatively little work for us to do in order to get our animations happening. You may want to download the file now as we’re going to use it later on in the tutorial.

Apple have neither released, nor endorse the functions CGSPrivate.h. Being undocumented, if Apple change this code then our animations will no longer work; the chance of that happening? Close to zilch.

The functions for workspaces can be ignored, unless you want to write another alternative to Desktop Manager or VirtueDesktops. However, the functions that we will be utilising are mainly CGSNewTransition, CGSInvokeTransition and CGSReleaseTransition. They should be pretty self explanatory, but I’ll go through them just to make sure we’re on the same wavelength.

CGSNewTransition creates a transition object with the ID of a CoreGraphics connection, options in the form of CGSTransitionSpec (transition type, transition direction, the window to apply it on, and the background color we want), and the handle by which to refer to the transition.

CGSInvokeTransition runs the transition with the specified handle for a certain period of time.

CGSReleaseTransition releases the transition with the specified handle from memory.

The Project

Project One - Cube Animation Through an NSWindow subclass

This project will be a simple window with a button on in that invokes a cube animation when clicked. It’s not designed to be useful, rather it will be our first animation project from which we’ll get the knowledge of CGSPrivate and it’s functions. We’ll create apps that actually do something a little on. The best way to learn is by example.
Let’s start up Xcode and create a basic Cocoa Application project.

Screenshot animation project

Call the project whatever you want, I’ve called it “animation”. Now you’ve get a screen with a mostly empty project.

Building the interface

You know the drill, go ahead and bring up MainMenu.nib in Interface Builder, and subclass NSWindow. I’ve called my custom class AnimWindow. Bring up the inspector and add the an action “turn:” which we’ll be using to animate our window.

I expect you know how to create files for the AnimWindow class and make the custom class of the NSWindow to AnimWindow. While you’re at it, you can also drag a button onto the window and connect it to the turn: action we just added. Save and close the nib, and let’s head back to our dear friend Xcode.

Screenshot AnimWindow inspectorAnim Window

I like to move it, move it

We’ve set the interface, but nothing happens when we run our application. It’s time to get our hands dirty and delve into the code.

As I mentioned earlier, we’re going to be using CGSPrivate.h, so download the file and add it to the project. Once the file is added to the target, open up the AnimWindow.m file and import CGSPrivate.h at the top of the file. This allows us to access all the functions found in the CGSPrivate header file. We’ll now add code to the “turn:” action to make the window flip around. Replace the existing blank action with the following code:

- (IBAction)turn :( id)sender

{
    // declare our variables
  int handle;
    CGSTransitionSpec spec;
    
    // assign our transition handle
 handle = -1;
    
    // specify our specifications
 spec.unknown1=0;
    spec.type=CGSCube;

    spec.option=CGSLeft; 
    spec.backColour=NULL;
    spec.wid=[self windowNumber];
    
    // Let’s get a connection
 CGSConnection cgs= _CGSDefaultConnection();
    // Create a transition
 CGSNewTransition(cgs, &spec, &handle);

    // Redraw the window
  [self display];

    /* Pass the connection, handle,
    * and duration to apply the animation
    */
    CGSInvokeTransition(cgs, handle, 3);

    /* We need to wait for the transition to finish
    * before we get rid of it, otherwise we’ll get
    * all sorts of nasty errors
    */
    usleep((useconds_t)(3000000));

    /* Finally, release all our variables */

    CGSReleaseTransition(cgs, handle);
    handle=0; 
}

This time, when you Build and Run, the whole window should turn into a cube and spin around when you click the button. That’s a full fledged animation in 15 lines of written code!

Cube Animating

We deal with getting rid of the black background later. For now, let’s examine the code we’ve just executed.

Post mortem - What exactly did we do?

The famous cube animation was implemented by a simple subclass of NSWindow, with only 15 lines of written code. We’ll start at the top, and go down through our entire AnimWindow.m file and see what’s going on at each particular instant.

AnimWindow.m

#import “AnimWindow.h”
#import “CGSPrivate.h”

We tell Xcode to include AnimWindow.h, and CGSPrivate.h. As I’ve reiterated a thousand times, CGSPrivate.h contains the definitions for the functions that give us access to the CoreGraphics API for transitions and animations.


@implementation AnimWindow

- (IBAction)turn :( id)sender
{
    // declare our variables
  int handle;
    CGSTransitionSpec spec;

    // assign our transition handle
 handle = -1;

Here we simply declare the variables that we will use later on in the method. The integer handle is what we use to refer to our animation object, especially when we have more than one.
We also declare “spec” as a CGSTransitionSpec. This will hold all the options for our transition, such as transition style and direction.
Lastly, we set the handle integer to -1. This can take any value, but usually it is best to leave it 1 or -1.


 // specify our specifications
 spec.unknown1=0;
    spec.type=CGSCube;

    spec.option=CGSLeft; 
    spec.backColour=NULL;
    spec.wid=[self windowNumber];

We set up our transition’s options. CGSTransitionSpec takes the parameters of unknkown1, type, option, backColour and wid.

  • Unknown1 is best left at 0 until someone finds out what it’s for.
  • Type refers to the type of transition. We’ve put in CGSCube here, but it can be anything from the CGSTransitionOption integers defined in CGSPrivate. For example, you can change it to CGSFlip or CGSSwitch and see what happens when you run the project again.
  • Option defines the direction of the transition. Again, all the directions are defined in the CGSPrivate header file. We’ve used CGSRight here, but CGSLeft, CGSUp and CGSDown are all valid directions.
  • BackColour (with UK English spelling for some reason) is obviously the colour that the rest of the screen becomes during the transition. This takes an NSArray with three floats to specify the RGB values for the desired color. Sending Null, as in our case defaults to black. We will look at getting rid of the backColour in the second example.
  • Wid takes the window number of the NSWindow that we want to apply the transition to. We can get the window number of any window by passing the windowNumber method. In this example, we are applying the transition from the window to itself, so we pass a [self windowNumber];

 // Let’s get a connection
 CGSConnection cgs= _CGSDefaultConnection();

To run any function of CGSPrivate, we need to have a connection to CoreGraphics. Here we define cgs as a _CGSDefaultConnection(). In actual fact, we could omit this step and pass _CGSDefaultConnection() in place of cgs when we do so later on, but doing this step means less typing afterwards and easier to follow code.



    // Create a transition
 CGSNewTransition(cgs, &spec, &handle);

Obviously creates a new transition. We pass on the connection (cgs), the specifications (spec) and the handle. We use the handle to refer to this transition rather than making a pointer to it, like we would most objects in Cocoa.


 // Redraw the window
  [self display];

Forces the window to update. If we don’t redraw the window, the transition will happen, but any changes we wanted to come up will be shown after the transition. Not much of a problem in this sample since we don’t have any content on our window, but we’ll be getting to that.


 /* Pass the connection, handle,
    * and duration to apply the animation
    */
    CGSInvokeTransition(cgs, handle, 3);

Applies the transition. This is the line that causes the whole world to go black and the window to “cube”. We need to pass the cgs connection we made earlier, the handle to identify which transition to invoke and finally the duration in seconds. For a smooth transition, duration is generally best left as an integer between 1 to 10.


 /* We need to wait for the transition to finish
    * before we get rid of it, otherwise we’ll get
    * all sorts of nasty errors
    */
    usleep((useconds_t)(3000000));

    /* Finally, release all our variables */
    CGSReleaseTransition(cgs, handle);
    handle=0; 
}
@end

We need to release the memory used up by our transitions, but if we release anything while the transition is still going, we’ll muck things up. For this reason, we tell the system to wait for the transition to finish by the usleep function. We pass whatever duration we had times 1000000. In our case, 3 * 1000000.

The next line releases the transition from memory. We just need to pass the handle to identify which transition we’re interested in removing, and that’s a wrap! Congratulations, you just pulled off a CoreGraphics animation in 15 lines of written code!

Download Source


Getting Serious

The sample project in this first tutorial was great to demonstrate the use of CGSPrivate, but it could have been written better. In the next part of this series, we’ll be to putting our knowledge to work, and creating an app that actually does something. Stay tuned.

Our Second Project - Setup Assistant (coming soon)



Was this article useful?

Let me know if you found this useful, for motivational purposes. Any feedback or criticism is welcome to improve the scope of this article, and remember, part two is coming soon, which expands on our current knowledge and introduces some new concepts; not to be missed for the world.


Back to Top ↑

38 Comments so far

Leave a comment

Pages: [1] 2 » Show All

  1. 1

    This is a kick ass tutorial, and very easy to follow. iam completely new to Core graphics and cocoa in general and this is by far the best tutorial i founded yet
    thanks and keep up!

  2. 2

    Thanks, Alejandro. The reason this tutorial was written was the lack of good CoreGraphics documentation around the internet, especially since Apple haven’t released it publicly yet.

    Do keep a lookout for part two, as it’ll expand on our current knowledge and part three will deal with CoreImage with which you can do a plethora of awesome animations.

    I am a little curious to how you managed to find this site, though. I haven’t even started advertising it yet!

    Thanks for your feedback, I do appreciate it.

  3. 3

    Ankur, i found it here http://technorati.com/tag/cocoa?start=10

    only 2 posts and i am already suscribing to your Feed!

    To make things more bizarre, i am from Argentina, there are close to none Cocoa developers here, (all the Apple hardware is really, really expensive!) so i guess iam the only one you’ll ever see on your site stats coming from the south :p

  4. 4

    Thanks, Alejandro.

    I’ve heard about Argentina’s lack of Apple hardware before. It must be hard being a cocoa developer there. Hopefully there’ll be an increase in Mac users there as the Intel chips, Leapord and it’s “secret” features roll out.

    As for CoreGraphics, I’ve uploaded the source code for the sample project. Do show me if you do anything with it.

  5. 5

    Your article is well written, bravo. There is one small detail that I take issue with.

    Apple have neither released, nor endorse the functions CGSPrivate.h. Being undocumented, if Apple change this code then our animations will no longer work; the chance of that happening? Close to zilch.

    Um, no. We have no way of knowing how Apple’s internal development works. They could remove those functions at any time. If and when people’s code breaks because something changed who do you think they’ll blame, you or Apple?

    Don’t be a fool and ship products using undocumented code. File enhancement requests at http://developer.apple.com instead.

  6. 6

    Harvey: I agree with you completely, however, since most of these functions are in use already with expose, the genie minimize and fast user switching, I don’t think this would be much of a problem.

    If that still doesn’t satisfy, I will be releasing another tutorial on how to complete these and other (cooler) transitions and animations using Core Image - which is 100% documented :D

    Thanks for your feedback, and if you have any more concerns, do reply back.

    There is a (more fiery) discussion regarding this here.

  7. 7

    Hey, that’s an awesome tutorial!

    There is one little thing I noticed though: The interface (buttons etc.) still work while the transition is in progress, you should block the interface. I’m not sure how you’d do this though…

    (Oh and I’m suscribing to the feed too ;) )

  8. 8

    Thanks. Locking the interface is a great idea. I’m currently working on part 2 of the tutorial, and I’ll be looking to implement that in. The next part will also deal with removing that annoying black background that comes up when the window animates.

    Thanks, all, for all the feedback. I’ll try my best to accommodate everything where possible.

Pages: [1] 2 » Show All

RSS feed for comments on this post. TrackBack URI

Leave a comment

Comments may be edited for formatting.