Michael Levy: Welcome to the session on Core Animation in Practice part 1.
My name is Michael Levy.
I'm an engineer in Quartz Technologies, and I'll be assisted today later by Tim Oriol.
My expectation about you, the audience, is that you're either new to the platform or perhaps you published the couple of apps, but you haven't ever worked with Core Animation directly.
So that's why it's part 1.
And what I'm hoping to do today is to give you a real sense of how Core Animation works, what our thinking was that when behind it, how it makes it a lot easier for you to bring your own applications to life.
So what will we cover in this talk?
There are really three main parts to the talk.
We will talk about layers and their properties.
We will then talk about how you provide layer content.
Now, there are number of ways to do that.
I'll talk a fair bit about Core Graphics, and then I'll briefly mention some of the other technologies that you probably heard quite a bit about at the session so far, including UIKit, OpenGL ES, and the new AVPlayer framework.
And then finally, we will get to probably the most fun part of the talk, which is actually animating layer properties.
So before I even start going there, I want to give you some sense of the architecture itself.
So as with all our technologies, it's layered.
And you can see UIKit sitting there at the top and the Graphics Hardware sitting at the bottom, just above that OpenGL ES, and Core Graphics users, Core Animation.
Now you from your applications, if you're new to the platform, understand that you can reach any of these layers if you need to.
But as you go up this layer hierarchy, it gets more and more of the work's taken care of for you.
What we tried to accomplish with Core Animation is to do all the complicated stuff behind the scenes, making it very easy for you to get the animation effects that you need in your apps without having to reinvent many complex and sophisticated algorithms.
And roughly, the way it works is that you're application will have a layer some sort of layer hierarchy like this.
You in your program, you set one or more layer properties, and that will automatically get rendered frame by frame as it needs to, will do the computation of the intermediate frames, and they will appear nice beautifully smoothly on the screen that you have.
Before I proceed though, I should just talk about UIKit.
So which should you use if you face this, the practical problem?
And the answer is you can leave now because really, almost always, you should use UIKit.
So when would you use Core Animation?
Well, a good example would be if you have a lightweight animation that you want to achieve, or perhaps you have something that is very short-lived.
But over and beyond that, it really helps you to understand Core Animation because that will make it possible for you to write much better apps.
You would be more effective even if you all you use are UIKit Animations, because all the UIKit Animations are really wrappers [phonetic] on Core on equivalent Core Animation, or maybe they aggregate Core Animation objects.
And of course, it may be necessary to improve a performance, and then, it's very helpful to understand what Core Animation is really doing for you.
So with that, let's plunge in to the first part of Core Animation, which is Layers.
And so, what are layers?
Before I even say what I must do the definition of Animation.
So the Oxford English Dictionary says Animation is the state of being alive.
Now, what that actually means in practice, or rather, when you apply that to Core Animation, there's another way of thinking about it, which is animation is changing the values of your model properties over time.
So that's really what we mean when we say an animated application.
There's another definition I'd like to introduce as well, which is declarative, because you'll see that mentioned quite a bit in the documentation.
And I thought of a good example of that.
You arrive at San Francisco Airport, you've never been to San Francisco before, you hail a cab outside the terminal, and you say to the driver, "Take me to Moscone West, please."
Now, that's your declaration.
You don't say to him, "Turn left at highway 280, and then take the first on-ramp."
That would be the procedural root.
Now of course, you all know that the driver may not take the optimal root.
So if you knew more, you might want to dig down and say, "Well, why are you going that way?"
Or, "This is going to be slower."
So that will give you sense of declarative.
I think the metaphor works quite well.
And the magic source of Core Animation really consists of three parts.
There are Layers, that's the first part, then the fact that almost all the properties of layers are Animatable, and finally, there's Declarative model, which in many instances, means you don't even have to implement a drawRect method.
So let's look at that in a little bit more detail now.
We're looking at the Layer hierarchy.
At the top is the object CALayer.
It's not abstract.
In many instances, you will instantiate that directly.
But they're in a whole number of interesting sublayers.
I'll cover some of them in the talk.
So for example, the CAShapeLayer, we'll see some examples.
It's a Layer, but it has an additional property which let's you set it shape, and we'll see how that works.
So this chosen example, which I hope is familiar to everybody, just to give you an idea of how this layering works.
Now so there's the ace of hearts.
And you could of course, implement this by drawing all the pads, and so on.
But another way to do it using is to break it down into its constituent Layers.
And Layers can be lightweight objects.
So here, I've composed this the back of the card, which is the layer, which has some properties like rounded borders, and it has a stroke with a white fill color.
And then the two heart the three heart tips there's one yeah, the three heart tips are ShapeLayers, and the two ace are TextLayers.
And so, we add all those as sublayers of the card layer.
And when they user sees that, that's what they see, the ace of hearts.
So it give so Layer, appropriately named.
How do you create a layer in your application?
You use the QuartzCore framework, which is not included by default in any of the Xcode template.
So remember to add it in, and then you need it wherever you're using one of the Core Animation Layer classes, you need to import QuartzCore.h. And there's a very simple example, it illustrates the declarative style on creating a layer using a the Layer method class method of the CALayer class.
I'm setting the bounds, the width, and the height.
The position is setting a point with respect to the parents coordinates.
I haven't placed the layer yet.
But when I do, that property tells the parent layer where to position this its sublayer, which will be my layer.
And then notice how the easiest way to give a Layer actual content, visible content, is to assign an image to the content property of the layers.
And there, you're seeing, the diagram finally, of course, add the sublayer.
We're using a layer method on in this case, I'm assuming there's a UIView.
And every UIView, as you probably learned earlier today, has a Layer property.
So I'm adding this as a sublayer to the view.
The blue that you're looking at is the UIView's Layer.
And the text is just descriptive.
So you're seeing where the layer has been positioned.
And it has got and that's all you have to do.
If you write this code and add it to your init method, that's what you will see on the window.
The Layer model's very similar to the UIView model, which I assume you somewhat or may be familiar with.
That is the method is like adding a sublayer, you can insert layers above or below other layers.
There are methods like setNeedsLayout which give you application and opportunity to move the layers around, setNeedsDisplay which is to tell now, in many cases, you don't need to call that.
But in cases where the system doesn't automatically know that it needs to refresh the screen, you would use setNeedsDisplay, and you can explicitly force out a new layout of your sublayers by calling the layoutSublayers method.
And there are many others, as I say, similar to the UIView equivalent UIView methods.
It's a 2 1/2 D Model, and the transform, we will see some examples of the transform, is a three-dimensional affine transform.
And what I'm showing here is another playing card, the ace of spades, and I'm the diagram is showing the layer hierarchy.
So I have the UIViewsLayer at the top, it's got a sublayer, which is the card.
Now, the card is simply specified with a couple of properties.
One of them is rounded rectangle, and then it has a background color of white.
That's all I had to do for the card.
And then I've create three shape layers, given them all the same Bezier path, we'll see this example a bit further on, but I've set the transform property and the position property to put the pips in the appropriate place.
And then there are two CATextLayers for the indexes A, and again, I used the position and the transform to position and orient those shapes in the right place.
So let's work this through, and you'll see how it all works.
And really, what I'm trying to illustrate here is there's no drawRect code involved.
It's really just setting properties and letting the core animation framework figure out the details and render it correctly for you.
So we will start by adding the card itself, and I have just deleted the various properties, but they're pretty straight forward.
They're like, you know, border styled, and so on.
All nicely documented.
OK. Now, I'm assuming that I have classical cards, which you can think of as a card factory.
So I've ordered from the card factory a ShapeLayer, and I've said to it, "Give me a spade pip."
Now, inside there, there will be the Bezier path that defines this the spade shape that I want from my playing card.
I set the position to be in the middle of the card fairly straightforward, and then add it to the spade ace, the card.
And so, that's what will happen.
The next one is a little more interesting.
I ordered the same ShapeLayer, an identical copy of the spade pip.
But in this case, I want to spin it around by pi radians and I want to position it at the bottom right hand corner of the card, and then again, I add it the spade layer, and similarly for their remaining.
I think now, you get the idea at similar for the remaining parts of the layer.
So it is important when you're using Core Animation to understand the geometry of layers.
In some ways, if it's simpler than UIView geometry.
These are the important properties that you need, the bounds, mostly the width and height, the position, and as I have mentioned, that's in the superlayer coordinates.
So that tells you where this layer goes with respect to its parent.
The anchorPoint, which I'll talk a bit more about in a second, and then the Transform, which is a three-dimensional transform, and I'll again, in the demos, we will some uses of the three dimensional aspect of that transform.
But very commonly, if you're doing a two-dimensional app, you will just use the 2D part of it.
But the 3D is available there for you as well.
The anchorPoint now is a point, and it's really meant to indicate where within the bounds, the meaning of certain other properties.
So for example, if you think your position its positioned with respect to the anchorPoint.
So and that's specified as a CGPoint, a floating a pair of floating point numbers, and they both range between zero and one.
So in this example, we're looking at an anchorPoint of 0.5, 0.5, which is the default for anchorPoint.
So normally, you don't have to actually specify that if you're happy for your anchorPoint to be in the middle.
And I'm just showing explicitly now, if you do an anchorPoint of 0.5, 0.5 and then do a rotationTransform, then the transformation will happen around that anchorPoint.
Let's suppose you set the anchorPoint to the bottom left of the layer.
How do you do that?
Well, we do it by specifying a point of zero and one.
So zero in the X coordinate, and in this case, my coordinates system is starting from the upper left.
So one represents the maximum Y value of my layer.
So that's what positions it at the bottom left hand corner.
And you can see that the rotations same rotation is now applied around that anchorPoint.
And I would like to demonstrate a slightly unusual use of this, plus the use of layering.
What I did to create this very little code to do this, but I wanted to illustrate a couple of things.
So one is a nonstandard use of anchorPoint.
So I wanted a model, the human arm, and I wanted to get a fairly realistic way.
Now, to do that, you know, with a sophisticated animation, would take a lot of knowledge of human anatomy and so on.
This is a very simple model.
I attached the arm you know, the arm bone to the shoulder, and then I attach the radius and the ulna to the humerus, and I attach the wrist.
So there and that's sublayered.
So I've got three sublayers, as well as the body, which is not showing here.
The head is just put in for effect.
Each of the rotations has its own little animation, and you'll see how to do that.
So diagrammatically, this is what's going on.
Now, to specify the anchorPoint is pretty easy.
The X coordinate would be zero, the Y coordinate of the anchorPoint would be 0.5, and then the sublayering attaches the body in the way I want.
And obviously, by tweaking the anchorPoint, you could make for stretcher or narrow the hands.
So that's mainly, I wanted to illustrate both the concept of layering and the utility of anchorPoints, and I wanted to sneak in the fact that when you hear about animation, you think, well, is this is like, you know, cartoon time.
Well, yes, it can be.
They can be you can add image content and you can have an entire animated movie using the Core Animation classes.
Much more commonly, you will use it for you for your visual elements of your application, but there's no reason to do this kind of animation.
Now, I want to take a slight detour now and talk about providing layer content.
And I'm going to talk about four different ways of doing that.
In some detail about Core Graphics with the assumption that you've might not be familiar with Core Graphics directly.
You've used it indirectly over time because of where it fits in UIKit.
And then I'll just talk very briefly about Open GL ES, AVFoundation, and UIKit itself.
Let's add a little bit about that.
So supposing that the clarity of style that I've been talking about has not given you enough control over what you want to display.
Well, in that case, there are two ways to actually provide additionally content.
If your layer object is just an instant of CALayer, then you set its delegate property to one of your own objects, and your own object must implement drawLayer:InContext:.
The alternative is to sublayer the CALayer with your own Layer, in which case, you must implement at least the drawInContext method.
And in both cases, the context argument will be something called a CGContextRef, which is what I'm going to talk about quite a bit coming on.
Note that very often, you do not need to subclass CALayer.
And this was part of the design.
They are meant to be usable in lightweight situations where there's no need for an additional class in your already quite complex set of classes.
You can just instantiate CALayer.
Nevertheless, by using Delegate, you can provide draw in code, and you'll notice that the delegate method takes a layer argument so the same delegate object can do double duty if it needs to.
So let's talk about Core Graphics a little bit, also known as Quartz 2D.
And Core Graphics is really at the heart of all the 2D the beautiful 2D graphics you see on any of the Apple devices.
Mac OS X, on the iPad, on the iPhone, on iPod or the iPod Touch, at least.
It's a concise and elegant model that gives you full 2D graphic capabilities.
I've picked a sample from the iWork's pages template, and I chose this example because it illustrates the three fundamental primitive elements that Core Graphics works with.
There is the image that you see, the picture is the one, and then there are shapes.
So you see a big red rectangle, then the black lines, and the black rectangle.
And then finally, text the glyphs that you've seen the text.
So that's showing all the three primitive elements.
Comprehensive color support, Resolution independence, Device independence, that's all taken care of for you automatically.
And the other nice thing about Core Graphics is you can create a number of different kinds of context, you use exactly the same methods and cause to, for example, going around this around counterclockwise to generate a bitmap, to generate a PDF document, to render on to an iPad, or to render on to an iPhone.
And in fact, to render on to OS X too.
So I don't want to give an entire course in Core Graphics here, but I thought I'd like to give you the spirit of it so that and then I'll give you a reference to a very nice book so that you can followup if you need to, to found out more about it.
So the coordinate space is an abstract to dimensional space, the units of floating point numbers.
And just bear in mind that a point is not necessarily a pixel.
And then as screens gets higher and higher resolution, it's important not to confuse those two things.
Generally speaking, the origins at the top left or the bottom left of the device that you're looking at.
So on the iPhone, it's in the top left, PDF's bottom left, and so on.
And of course, you obviously have to know that.
And then there's this important object called CTContextRef.
So it's an opaque reference to a graphics context.
And there really are two parts to a graphic context.
When she grasped back the ref, becomes pretty straightforwardly.
There's the place you're going to actually render to, in this case, the artist's canvass.
But there's also the implements that you're going to use and the state they're in.
So there, you're seeing in the picture, an easel has some paint premixed, and maybe there's a paintbrush in the artist's hand, and that's got a particular color on it.
And that's all part of the context object.
So the drawing destination and the state.
So notice the state has a number of properties, including path, fill and stroke colors, line width, and so on.
And the state changes.
So it's state-based model, so you set a fill color for example.
And then the next, all the fields that follow setting the fill color will use that color until you set a new fill color.
It's a C-based model.
It uses reference-based memory.
There's a little protocol that you need to learn.
So if you're using this for the first time, you need to learn the conventions to make sure your applications don't leak memory.
It's CFType compliant.
I'll illustrate the sense of it with this made-up example.
So let's say you want to create a stunning color, and you already have your color space chosen, and you've set your color components, you call the Core Graphics method CGColorCreate.
Now, notice the Create word, that's the key that says to you, you own this memory.
If you own it, you must release it when you're done with it.
So having created the color, we want to use it now.
So we changed the state of the graphics context by calling CGContextSetFillColorWithColor.
Now, all the state-changing methods of the Core Graphics context will start with CGContextSet and something.
So once you get used to that, very easy to find the method that you need.
Now, having done that set, if the context, the graphics context, wishes to retain a reference to that object, it's free to do that.
I don't care I don't know what it does.
Maybe, it copies the components somewhere else.
Irrelevant at this level.
What I do know is because of the word create, I have to release the memory.
So I called CGColorRelease with my color object.
So let's work through a small example now and make all these concrete.
So back at the playing cards, sticking with the playing card theme for the time being, now, if you play team games like bridge, you know, you want the card designers want to make it very hard for you to signal additional information to your partners.
Same thing applies for poker.
So perhaps your design requirement for the back of your playing card is that they had two-way symmetry.
So let's see how we might achieve that.
Now, what we'll do is we'll use a stroke and fill path, and that's what our card's going to look like, except that, since it's going to be two-way symmetrical, I only need to render a quarter of it, and the rest, I can do with appropriate transformations and positioning.
So there's our basic design.
Now, because it's a state based model, it's always nice to save the current state and prevent nasty surprises to your caller when you go changing things like the fill color.
So that's the call that will do that.
It's an efficient call, won't cost you much.
Now, I'm going to create something called a CGPath.
Now CGPath is a Bezier path, good old Bezier path, I'm creating a mutable one because I want to modify this path.
And here are some of the lines of code for creating that petal shape.
So I'll move to some starting position, add a curve, it's the usual Bezier path, move to add another curve, and there are other way, the lines, and so on there.
And once I've done all that, I add it the Core Graphics context, and then tell the context to fill the path.
And visually, that's what if you return from your draw method at that stage, that's what you would see.
Now, when you call fill path, Core Graphics deletes the current path.
So if you want to use the same path again in order to stroke the flower, you have to add it back.
So let's a tiny little gotcha, we add the path back, and now we call CGContextStrokePath.
And I'm assuming that the fill color and the stroke colors have already been set up.
And then with a little bit more work, you can see that I will get the center and the petal.
Now, the next part of it of course, is repeating that, but in four different positions and making them all join up.
So there, we'll use Affine Transforms.
And an Affine Transform is used for scaling, rotating, and translating.
They can all combine into a single matrix skewing as well, but it's less common.
And the trick to making your life more pleasant when you're working with transforms is just remember that what you're transforming is the coordinate space, not the object.
So every object that gets applied after transform will go into the transform coordinate space.
So let's work through this example.
We would be nice to our caller.
I'm assuming now I have a drawDesign method, so it will draw our basic design.
And now, I want to flip the card and move it down.
So I do this with the two calls that you are seeing there.
Flip is done by changing the by scaling the Y coordinate to be negative, and then I translate twice because the first flip will put the coordinate space, or flip above the first cards, so I want to go down twice the height of the card.
And very similar transformations for the rest of the card, and then we'd be nice and restore the graphic state.
Now there's a quite a lot more to Core Graphics.
I'm just going to give you some examples here without going into anymore detail.
It'll take care of anti-aliasing for you, which would be very nice if your app the same code you run now, running on the new iPhone 4, and you've got the retinal display, the Core Graphic framework will take care of making sure that you get those beautiful smooth lines.
There's gradient fills, shading, which is a more complex fill, pattern, such as that familiar pattern, and many properties of lines, line caps, strokes, and so on.
And there's quite a bit more, all nicely documented in our documentation.
And can you read that?
There's a very nice book I recommend if you want to follow up on this, called Programming with Quartz 2D and PDF Graphics in Mac OS X.
And there's one more tip on Core Graphics.
So Core Graphics, if you can remember the layer of hierarchy that I showed you earlier on.
So Core Graphics comes underneath UIKit.
And so, when you want to do things with Core Graphics, sometimes it's a bit more programmatic work.
So a nice tip is use UIKit.
So to just give you a trivial example, if you want a red color, it's a lot easier to say UIColor redColor calling the UIKit class method, and then get the CGColor property out of it.
And a nice example is loading an image.
It's very easily done.
There's a UIKit method say a UIImage method, class method, saying image name, then it will grab an image from your project.
If you actually need the CGImage for some reason, then you can just get the CGImage property of the image.
So it's very useful to let UIKit do the heavy lifting, and you just pick the object.
So that's Core Graphics.
This is going to be just a slide on each of these.
You'll probably tend to talk about the game Quest now.
And what I wanted to point out is almost everything you're looking at visually, when you play the game of Quest, is actually is actually a CALayer.
The only exceptions are the rendered dungeon model and possibly the character, which we have done with OpenGL ES.
So everything else is really a CALayer.
Now, it might be indirectly through a UIView, but the point is we're using layers on the top of OpenGL ES.
And you can turn that round.
You may have an application which is mostly just sort of conventional UIElements made of CALayers, and one of those layers could be an OpenGLES layer in which you can do your sophisticated OpenGLES rendering.
And it all integrates completely seamlessly for you.
Another example, I've just taken from the YouTube application what I'm trying to illustrate there is the use of the new layer object that's been introduced with iOS4 which is the AVPlayerLayer.
Now, it's very easy to use the AVPlayerLayer.
You can set its URL to a movie, and then you can add the AVPlayerLayer as a sublayer to your views layer, which is what you would do here.
And there, we're seeing a couple of other layers with some nice properties like opacity and so on.
And that's it.
Very simple, and again, all integrate seamlessly together.
And then finally, UIKit.
So it turns out on iOS 4, every UIView object has a layer a CALayer object behind it.
It's sort of comes for free.
Normally, you don't have to worry about it or even get it any thought at all.
And the default is an instance of the CALayer.
You can overwrite the default by providing a layer class method for your UIView subview, and you can either provide one of the CALayer subclasses like CAShapeLayer, for example, or you can use your own subclass, in which case, anything that you do with the UIView will actually be using your own layer of subclass.
OK. So that's covering providing content.
And now, we're going to get to the heart of this presentation, which is Animation.
So remember, the dictionary definition is, you know, bringing something to life.
So we're going to hopefully bring all your applications to life.
So what does animation actually mean from a programmatic point of view?
It really means changing the value of a property from some starting value to some ending value over time.
Now, we used Position a lot because that's the obvious one.
But as we'll see, as we progress, there are many other properties that can be animated to good effect in your application.
But let's start with the basic.
Now, it turns out that whenever you change one of the layer's properties, you will automatically get an animation.
So you remember that render diagram I showed you early on, which showed the individual interpolated frames, that happens automatically for you.
So here's an example.
I have the original layer I showed you with where the contents was the Core Animation logo image, and I'm going to set the position property of the layer.
And but now, not totally satisfactory because it started, you know, it went to infinite speed and stopped doing, you know, so a bit unsatisfactory.
So it turns out that when you set a whole bunch properties of layers, the next time the run-loop gets controlled, it implements a transaction.
The transaction will cause all the layer properties that have changed to animate in the way that I showed you on the slide with the jumping presentation that it has.
So if you want to overwrite some of those default properties, you use a classical CATransaction and that allows us to overwrite some of the default.
So in this case, we want our animation to last five seconds, and we want to use a tiny function called EaseInEaseOut, which will allow this to behave in a bit more realistic way.
That is it'll speed up, reach its max speed for a bit, and then slow down.
Now, remember, I said all the details will be worked out.
So you don't need to do anything else.
You don't have to do additional math to work that out.
You can forget your Calculus 101.
Don't need it.
But you do know that you want this nice timing function, and there goes a much nicer looking animation.
And I timed it.
It is five seconds.
Now, it's obvious to think of Position.
I keep mentioning that.
But I just wanted to get you thinking, because really, there are other properties.
So I put down some of the meanings.
So for example, there's an opacity property, and it ranges from zero, invisible, to one, fully visible.
If you animate that property, you would get a fade in or fade out effect.
The shadow properties make the shadow appear or disappear.
There's Transforms which will obviously, move your object in 3D space.
So a bit more general than Position.
Bounds, you can grow and shrink objects.
In fact, almost all the Layer properties are animatable.
You're limited only by your own imagination in how to use the animated animatable value of these properties.
And I haven't covered this, but you can even animate your own properties if necessary.
I've mentioned the transactions.
So the way to think about this is I have my Layer tree, I settle my properties, the run-loop gets controlled, it checks to see look it looks for property changes, that's the transaction, it uses the CATransaction class, you can set things like the duration, the timing function, as I illustrated in the previous slide, you can also have explicit transactions using CATransaction Begin, set your properties, and do a CATransaction Commit, and those can be nested.
I'm not going to go into that in this talk, again, nicely documented.
Now, once in a while, Animation might get in your way.
So here's a handy tip.
If you want to turn it off, then you would use the CATransaction setDisableAction, and I'm going to turn it over to Tim to show you the difference between doing that and not doing that.
OK. So what Tim's going to do is he's going to move that logo around the screen.
And you'll notice the lag as he moves his finger, and that's because we're setting the what the app's doing is very simple.
It's detecting the touchpoint and then setting the position of the CALayer to be where the touchpoint is.
But it's animated.
So there's a default duration that and a default timing function, in this case, linear.
Now, the switch at the top, when turned over, will cause our application in each iteration before we set the property to say, if that switch is on, disable the action.
And now, of course, this you know, this will look might be a slight lag That's the GPU working hard to do all the work it needs to do, but it in this case, it will track the finger much more closely.
OK. I'm going to do another example now of Implicit Animation, and in this case, getting back to playing to cards.
I chose those just because I could assume that almost everyone in this room has seen playing cards.
And so, I don't have to explain them.
But in this case, I'm assuming that I have three cards that are stacked one on top of each other, and at some stage, I want to fan them out.
I've just chosen three because it's the smallest number I could get away with that showed a fan, and I didn't want to bug you down with too much detail.
So I'm assuming that I'm going to have an array, just a normal array of its its type is CALayer, they have three elements of this array, and I'm going to populate each of the elements of their array with an instance of a CALayer object, that's the third like of code there.
They're all going to have identical bounds and position.
And then the important thing is I'm going to because I want to do a fan, I'm going to set the anchorPoint to be the bottom left hand corner of the card.
If I rotated them around the center, we'd still get an effect, but it would be different from fanning the cards out.
The usual objective of fanning cards out is to show all the card indices.
So you really want to rotate around the bottom of left hand corner.
So the only thing that's different on this in this loop is that I give each of the contents a different image.
So I'm assuming that I've preloaded an image array with card images, and then we add them sublayers of the view, and that's what it will look like before I do the animation.
So how do I do the Implicit Animation now?
Well, what I'm going to do is Transform I'm going to change the Transform property of each of the cards.
In the first case, I'm going to rotate by three degrees to the left.
The second one is actually redundant.
I'm doing no transformation, but it doesn't hurt to stick that in.
And then the last one, I'm going to rotate by three degrees clockwise, and we'll see how that looks on the demo.
I've added just one more tweak because it is visually it gives you the real sense about its layers.
So I'm going to ask Tim to push another button, and that's going to cause the queen of hearts to go sport of sliding underneath the other two cards.
So just so it really has the feeling of layer.
And there's more sophisticated stuff you can do with that, but I thought that would give you a strong sense.
So but thanks, Tim.
So that's Implicit Animation.
And I've just shown you how easy it is to do that you have control over the timing of the timingFunctions, there were number of properties that you can animate.
Sometimes, you want more control of your animation.
And in that case, you would use what's called Explicit Animation.
So what we're looking at here is the Animation hierarchy.
Now, in this case, the roots of the Animation hierarchy, CAAnimation, is abstract, as is CAPropertyAnimation.
The ones that you'll typically use most often in your application are the remaining ones, CABasicAnimation, which as the name implies, is a basic animation, CAKeyframeAnimation, which we'll talk quite a bit about, CAAnimationGroup, which lets you bunch a whole lot of animations together onto a layer so you can animate opacity, position, transform, you can do all that simultaneously, and then I'm going to talk very briefly about CATransition, which is a little unfair because mostly, what you'll see when you're running apps on the devices are actually, transitions.
But we'll talk about that a little bit later.
And I'm showing here some of the properties that are important, but we'll go into enough detail for you to understand the basics.
So firstly, when you create an animation I'll start with basic animation.
How do you tell the Core Animation framework which property it is that you wish to animate?
The answer is you use a keyPath.
It's a string.
So for example, position or position.y, or anchorPoint.x.
And there in the line says Animation =, that's how you do it.
You instantiate a CABasicAnimation object, you use a class method called animationWithKeyPath, and the argument you give, it's just a string and it's the name of the property that you wish to apply the animation to.
Now, of course, that's not quite enough.
If you remember the slide where I said it was a graph, I said, "What is an animation?"
And I there were two important properties, the fromValue and the toValue.
So after you've created the basic animation, you typically want to specify a fromValue and a toValue.
If you don't, the default is the current model value, in which case, the Animation won't do anything.
Very often, it's sufficient to just say toValue.
And then, how do you actually get the animation to kick off?
You add the animation to the layer.
So there's the call layer addAnimation:animation.
It's important to note that you haven't changed your Layer model.
That is, while the animation's occurring, all the presentation frames are changing, your model's unchanged.
If your program queries the model during the animation, it will get the old value, it won't get the current presentation values.
Could that be a problem?
Occasionally, and I'll show how to deal with that later on.
So let's start with a very simple example.
We're going to drop a ball.
So we're going to animate just the Y code of its position property.
So I give a keyPath which says position.y, and I want it to take two seconds, and I want the new value, the toValue, to be 300.
So I'm assuming it somewhere below.
And then I'm going to add the animation, and I'll talk about this key property.
But right now, I just picked some string.
You could also pass No in the forKey property.
In the next slide, we'll find a better use for it, and I'm sure you can predict can you predict what's going to happen?
Not quite what you might have expected.
So this is a bit of a beginner track for everyone learning Core Animation.
And when it first happened to me, I did a search on the internet to find out what I was doing wrong, and I have to say that all the answers I found were rather bogus.
[ Laughter ]
So now, I'll give you the definitive answer, and it turns out it's actually straightforward.
But really, the real reason I'm giving this example is because it will help you understand what's really going on.
And once you understand what's going on, it turns out it's rather trivial to solve this problem.
OK. So here's the way I should have done it.
Well, what's really going on is that the model value did not change.
And therefore, after rendering the animation, after the presentation frames were all displayed on the screen, the next time the screen was refreshed, the model value was used, and of course, the ball was back where it is where it was to start with.
So really, what I want to do is put the ball in the destination position.
Now, before I do that, I'd better save the starting position and you'll see why as I walk through this example.
So I want to set the ball in its target position.
Now, that line under the comment target position is essentially going to tell the layer that there's an Implicit Animation that has to be performed, and it's going to be an animation on the position property.
So really, by the time I've added the basic animation, there're potentially two animations going on.
Now, I may not want that because in my basic animation, I might have set a timingFunction and a time duration, and those might be different from the default for the Implicit Transaction.
So really, what I want to do is make sure that the Implicit Animation doesn't happen.
And the way I do that is by using the key, and I'd give the value for the key to be the name of the implicitly animated the implicitly animated property.
Now, why does that work?
Well, it works because what's really going on is that the CALayer has a dictionary of animations, and the animations are keyed.
And so, when I add that animation in the last line, it's just going to overwrite the one that had been set up by the Implicit Animation.
And so, the effect is that when the transaction finally does the actual animation, the Implicit Animation is history.
It no longer exists.
And now, the moment you will be waiting for the ball stays.
[ Laughter ]
[ Applause ]
OK. So that's basic animation.
Now, sometimes useful, but very often, you want to get a much more sophisticated effect, a roller coaster for example, slow, slow, slow, speed, speed, speed, scream, hands waving, and so on.
So then you might want to use key frames.
And so, just to remind you you might know this.
So when you rendering, you know, you don't always need to have a representation of every single frame.
So for example, on compressed movies, you know, the key frame has all the information.
But you can interpolate intermediate frames.
So it's exactly the same concept, their interpolated values and their key values.
When you make a key frame animation, you provide the key values, Core Animation will do the interpolation itself, and as we'll see in a second, you can also control the timing of the interpolation.
So how do you do a key frame animation?
Very similar constructive, we'll see an example in a second.
You have the choice of doing it in one of two arrays.
You can either use the path property of the CAKeyframeAnimation object, in which case, the animation will follow the path that you've specified finding the key the key frames as it goes along, or you can set the values array and you can use one or two, you need sorry you need at least two values, but you can have more, and they will be the key frame points, the interpolated points are worked out for you automatically.
And then to control timing, there's an optional array of key times, which is the fraction of the total time for each frame segment.
When you're actually doing animations, obviously, timing is very important.
So you often set the duration.
And if you want to do, for example, the roller coaster, then you would have to know for your particular roller coaster what fraction of the time there was in each part of that animation.
And then of course, the interpolation will be either between the values or along the path that you've provided.
So I'm going to do a more complicated example.
So imagine we have a playing card now, and we want to flip it around.
So now, I want to do a transformation, except not in this the normal transformations in 2D space or in the zed coordinate, because you're imaging your user looking down on the screen.
In this case though, I want to flip the Y direction.
So first, I'll set the transform, and notice that the CATransform3DMakeRotation call has four parameters.
The first one is the number of radiance that I want to do the transform in, and the next three are the is a vector that defines where the translation occurs.
So in this case, I'm using the vector zero, one, zero, which says rotate around the Y axis.
And now, I make my KeyframeAnimation again, I use a string, which is a keyPath, very similar, I'm going to create that animation.
Now, I'm going to do something a bit more sophisticated for the values.
Rather than trying to animate the transform properties, which is ultimately what I'm going to do, I'm going to use something called a valueFunction.
So I'm going to specify two values, zero and pi.
That is I want to animate between zero and pi.
But what I actually want to animate between zero and pi is a Transform around the Y axis.
So there's an extra property called valueFunction which I set on my animation object, and the particular value of function I want is the one that will take one of the values, either the key values or the interpolated values, and return the appropriate transform around the Y axis, and that's what Core Animation will apply to the count.
I'm going to make it last for two seconds, and then add it, and of course, same trick, yes, since I've already set the transform property, I want to get rid of the Implicit Animation and just use the KeyframeAnimation.
And this is how it looks.
Now, I have cheated very slightly, and I should come clean here.
I've used an extra property, which you can read up about, called the Sublayer Transform.
The parent layer has a sort of camera angle already set, so that we get a perspective view of that let me show it to you again so you can see what I mean.
So just just so you're clear, that the code I showed you wasn't the complete picture.
It's pretty easy though, to do the extra bit.
Now, you may want to combine animation, so that's pretty obvious, but I thought I would just illustrate.
I'm not going to show a movie of this, but just to give you the idea.
It's fairly straightforward.
Let's suppose that while the card is spinning, I also want to move it, and maybe I set a repeatCount on the flips, so that is spinning around and I want the whole thing to go spinning across the screen.
So in that case, I'd use a group animation, which is basically a collection of animations that are applied simultaneously to a layer's property.
So let's assume we already have created the KeyframeAnimation with the valueFunction to do the flip, and I want to move it.
So I create a basic animation, no need to be too complicated here.
I set the toValue, the 10 second duration, and now, I create a CAAnimationGroup.
Now, the group animation has a property called Animations, and that's just simply an array of all the animations that you want to apply one at a time.
I'm going to set a 20 second want to account for the fact that maybe I'm flipping the card twice while I'm moving.
And in this case, I don't need to delete any may not need to delete any Implicit Animation.
So I'll just use No for the key, and I have the group animation.
A few other things that are useful to know about, the CAMediaTiming protocol.
Now, protocol really is a contract that is adopted by class implementations.
If you're fairly new to the platform, this will be something you have to learn.
In this case, both CAAnimation and CALayer adopt the CAMediaTiming protocol, which means that they provide implementations of the properties that you're seeing below, and a couple of others.
TimeOffsets of and particularly important if you're doing a group animation, you want you might want part of your group to kick in later than other parts.
RepeatCount is nice.
Autoreverses is very nice because if you set that so for example, if I've done my ball animation with autoreverse, then I don't need to specify it coming back.
It will autoreverse, as the name implies.
And if I set the repeatCount to the maximum floating point value, then the animation will go forever, or at least as long as the user is looking at that particular screen.
Now, I mentioned a problem earlier on, which is what that the layer model is not changed, and maybe you care.
So in that case, for example, say, you're trying to do a hit test, you're implementing pong, and you want to you know, the user kind of touch the ball and you want to detect that hit.
So you can't use the model value because it'll still be what it was before you fired off your animation.
So what you do is use the presentationLayer, and it's very easy.
You just take your layer and you send it the method presentationLayer.
You would typically use it in two cases, I will illustrate both of them here.
So there, I'm doing a hit test, and I'm going to do another little trick here.
I'm going to use it to do an animation where maybe I care about the color and value as presented, rather than the model value.
So I will get the fromValue from my animation to be the value of the current.position rather than layer.position, and that will tell you where the object is as close as possible to when it was actually rendered, and the user is looking at it, and I'm adding a bogus animation.
In real life, if you tried this, it would just cause a little jerk, and then of course, you go back to the model value.
And then one more topic before the next step, which is Animation Notification.
So there are two ways to do this.
One way is to set a Delegate, and then you can get notified that the animation started, usually, more interestingly, that the animation stopped, and you might use that, for example, to clean up, get rid of sublayers that are no longer needed, and so on.
Another way to do it is to use the new block feature that's being added to iOS 4.
And so the CATransaction class in iOS 4 has a setCompletionBlock method, and you can pass it literally, a block of code that does the cleanup or whatever it is you wish to do at the end of your animation.
Now, the thing that comes to mind is animation chaining, and yes, maybe you could do that.
But you might also use some other timing since you got access to the media protocol.
You can also chain your animations using various timings.
But that's also a possibility.
OK. So what we've done is we've put together a sample code.
What I've trying to do is put up sample code that will make that will illustrate all the points that I've covered up until now, so you can very quickly go and look at it, and refresh your memory about what happened here and, you know, look at the code to get concrete examples of how all of this is done.
So there's the playing card made with the sublayers, as I have illustrated.
Can you touch?
Now, I'm doing a more interesting vector for my CA3DTransform.
OK. Another click, returning it back to its original state, touch [ Laughter ]
OK. Now here, I've used one of the layers I haven't talked about it a lot, which is the CATextLayer.
So each letter is a CATextLayer, and I just and I used the monospaced font so that my layer was very simple.
In reality, if you're going to layout text, you're more likely to use Core Text.
But this just illustrates to you a CATextLayer Touch.
And now, I'm using a timing notification to detect when the ball struck the text, and then I'm using a group animation, which simultaneously moves each of the text layers to a random position on the screen and does an opacity animation which changes the opacity from one to zero.
And that's how I get that effect.
OK. And I've got one more for this demo, which is I wanted to show that you don't have to use EaseIn and an EaseOut.
And wit you know, this gives a reasonable sense of a bouncing ball.
And in fact, I have just a linear timing function here.
Now of course, if you want realistic bouncing, then you have to go into complicated physics.
But, you know, this often would be good enough to give the effect of a ball bouncing.
Now, we're getting a bit low in time, so I'm just going to mention a couple of these classes, and then I'm Tim is going to do some pretty cool demos.
So I've talked about text layer.
I think you've heard a bit about CATiledLayer if you went to the scroll view.
But briefly speaking, a CATiledLayer is to deal with presenting content that's very big, in a way that doesn't kill the memory use on your device.
It also helps you zoom, so it uses mipmaps.
So it's a pretty useful class.
I've talked about shape layers quite a bit.
Tim will talk a little bit about Replicator Layers which are quite interesting.
And so, with that, I'd like to hand over to Time Oriol.
[ Applause ]
Tim Oriol: What I've done for you today is I put together two demos which sort of put together a lot of these concepts that we talked about.
We have a few layers on the screen right now, or fire hydrant is a CALayer with content provided by CGImage, the same with the nozzle.
The hose is actually using the CAShapeLayer, and we specified a Bezier path that will define the Layer.
And what I've done is when you detect a user touch, the shape layer will be constructed such that it will end up where the nozzle is, which follows the user's finger.
We've done the thing we've talked about earlier was we turned off the Implicit Animations when moving the nozzle.
So we get to follow the finger as smoothly as possible when we do this.
The handle on the nozzle is actually a separate layer, and we've set an anchorPoint at the base of the handle, so that we're going to animate it so it sort of depresses when we detect a second touch, and then we're going to use a Replicator Layer to sort of stream water out of the nozzle, as we can see here.
[ Pause ]
[ Applause ]
So you use the Implicit Animation to rotate that handle there, and then we have Replicator Layer which will create instances of all the sublayers.
We have one single sublayer, which is this water droplet.
And one of the interesting offsets there's a few offsets you can set in Replicator Layers is the timeOffset.
So if we apply this timeOffset when we animate one of these water drops moving out to the side, the other one will follow each after that timeOffset, and we apply a scale and a fade, we can get semi-realistic water stream here.
The final demo I'd like to show you also uses Replicator Layers.
And we use the sublayer transform to create a 3D effect as well in here.
And just so you can understand what's going on when I bring it up, this is three replicators.
We have one for the Extraction, one for the Y, one for the Z.
And I have a single sublayer that's used to create this entire sample.
And we'll add in the replicators one by one.
We'll add the Z and the Y and the X.
And so we have a single sublayer here with a color offset, position offset, and as you can see, a timeOffset to create this animating cube of layers using a single sublayer, and I apply an animation that will spin it and move it towards the camera and fade out, and that will be replicated to all of the instances after to sort of make it look like they're all coming out.
But you could do this all separately, and it's a lot more work and a lot more work at the timing, but this just show how the Replicator Layer can do a lot of the work for you.
And we have one animation to bring it all back in.
Michael Levy: So in summary, I won't go into some huge detail.
I talked about Layers and their properties, how you provide layer content, and Implicit and Explicit ways of animating layers.
I really hope you have a good sense now of how you can go out and get going with Layers.
If you have more questions, please feel free to e-mail Allan Schaffer, the sample code up already, there are the URL's for it.
Of course, the great Developer Forums, and I invite you to come to part two of this talk, which is in the same room, John Hopper will be giving that at 2 PM.
Today, it goes into more advanced concepts of Core Animation.