Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2007-210
$eventId
ID of event: wwdc2007
$eventContentId
ID of session without event part: 210
$eventShortId
Shortened ID of event: wwdc07
$year
Year of session: 2007
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2007] [Session 210] Building An...

WWDC07 • Session 210

Building Animated Cocoa User Interfaces

Leopard Innovations • 1:03:05

Delight your users with dynamic, responsive user interfaces. In Leopard, standard AppKit NSViews can be rendered and animated using Core Animation. Learn how to combine familiar Cocoa controls, views, and event handling with the power of Core Animation layers to create stunning user interfaces. James Dempsey and the Breakpoints perform at 51 minutes into the video. Encore of "Hold me, Use me, Release me" at 59 minutes into the video.

Speakers: Deric Horn, James Dempsey, Troy Stephens

Unlisted on Apple Developer site

Downloads from Apple

SD Video (283.8 MB)

Transcript

This transcript has potential transcription errors. We are working on an improved version.

Welcome to Building Animated Cocoa User Interfaces. I'm Deric Horn. I'm the application technologies evangelist. And being an evangelist over the last year we've spoken to thousands of developers about all of our new Leopard technologies. And overall, we're getting a really enthusiastic responses from all of your technologies in Leopard. And it's really great to see. But hands down, the technology that more developers are looking for more than any other has got to be animation. This is the technology that is really driving developers to write the next version of their applications for Leopard only.

So what we've done today is we've broken animation up into two different sessions. Today we'll present animation from kind of the view level, the user interface level. We'll take Q&A, and then give you about 15 minutes to jockey for seating, get better positions And then we'll present animation from the Core Animation engine layer.

How to bring those APIs directly up into your application and give it that really immersive experience. We also have coding headstarts for Core Animation. These coding headstarts can be found in your WWDC attendee area. And they include a video, a read-me, some tutorials, and sample code. One of the sample codes, for instance, displays how to use cover flow in your applications.

So before we start talking about animation, we should really define what animation is. And to do that, I turn to Mac OS X dictionary. And it says animation is the state of the being full of life, vigor, liveliness. It comes from the Latin term, animare. Instill with life. And I think animation really provides the means to bring the user experience of your applications to life.

It allows you to think about the way that you portray your data, the way that you're interacting with your users, and really change that. I think as developers, we tend to use lists and tables a lot. And this is kind of a paradigm that works great for developers, but may not always be the right paradigm for our users.

So at the same time, when you consider adding animation to your application, don't go too crazy. Keep things quick, meaningful, and something that really adds value to your users. So overall, I wanted to talk a little bit about the overall architecture. And when I think about the architecture, the heart of animation is really the Core Animation engine. The Core Animation engine really relies on layers. Now when I think of layers, I think of layers as these transparencies that sit on top of my screen.

I render my content onto these layers. I can then move them around. I can shrink them, grow them. I can maybe change the Z order by putting other layers in front of them. I can even apply these complex matrix transformations to them to make these layers swirl around the screen.

And we really get great performance out of this, because we don't have to rerender that content. Once its rendered on to that layer, we keep it cached. Now we further improve on that performance by letting it sit directly on top of OpenGL and taking advantage of the hardware acceleration that the GL pipeline provides.

And then we further improve on that performance -- because now all the machines that we ship have at least two processors on them -- so we allow Core Animation to run in its own thread. And then even to further improve on that, we rely on the multithread OpenGL layer. So you can see that we're really trying to eek out the best performance we can from this whole pipeline.

But at the same time, Core Animation is also this great graphics unification layer. And really what I mean by that is now we can start to render different types of content onto these layers. We can render QuickTime, OpenGL, Quartz Composer, text, we can render pictures or controls on these layers, and we can kind of coalesce them all and flatten them, so we can have an OpenGL background, controls in the foreground, or text scrolling above that.

Now in the past, this was pretty difficult to implement. One way of doing that would have been to create these child windows -- these invisible child windows -- and stick them all right next to each other. But then that really meant that we had to add logic into our codes to keep track of these extra windows.

And now we're giving that all to you for free. And then what I really think is interesting is we brought all this power that the Core Animation engine provides for you, and we brought it right up into the view layer. And that's what we're really here to talk about today is adding animation to existing user interfaces and to your views. And to do that, I'd like to welcome James Dempsey on stage.

( Applause )

Thank you, James.

- Thank you, Deric. Good afternoon. How's everybody doing this afternoon? That bad, huh? How's everybody doing this afternoon?

( cCheering )

That's somewhat better. Okay. My name is James Dempsey. I am an engineer working on the Cocoa frameworks, and today we're going to be talking about building animated Cocoa user interfaces. So let's get started.

So, we've noticed that over time user interfaces are becoming much more fluid, much more cinematic. We saw that going all the way back in the original version of Mac OS X, with the magnifying doc and the Genie effect, and all the way up through Leopard, even in bigger scale with things like Cover Flow and Time Machine. But we're here talking specifically about animating Cocoa user interfaces.

And in Cocoa, NSWindows and NSViews are the central classes that we use for implementing user interfaces. So we want these wonderful, rich cinematic animation experiences, and we're using Cocoa with Windows and Views. So what we've done in Leopard to make it easy for you is to add a simple flexible API to AppKit for animation.

Now, you may have heard of this thing called Core Animation, maybe once or twice already. We have this wonderful, new underlying graphics technology called Core Animation. And another thing that we've done in Cocoa and Leopard is to harness Core Animation and expose its capabilities and functionalities to NSViews.

So what we're going to talk about today. The first thing we're going to talk about is how ridiculously easy it is to animate Windows and Views. And I use that word very specifically because when you see the half line of code it takes, that's ridiculous. The other thing we're going to learn about is how to create and use views that are backed by these Core Animation layers.

And we'll get to that, and that we'll find is a whole line of code. So with this one-and-a-half lines of code you're able to take all that underpinning of OpenGL and then Core Animation built on top of it, and have that in your application. And then we have an extraordinary short presentation.

But these will get you all of the default animations that we have built in. However, there's a lot more that you can do. And so we're going to spend the rest of the time, or a good chunk of the rest of the time, talking about creating and using custom animations. So, keyframes following a path, grouping animations, using Core Image filters, and transitions.

Finally, we're going talk about mixing various content types in your application, and then we'll do some usage tips. So we're already, what, a few minutes into an animation session without a demo. So I think we need to rectify that immediately. And so I'm going have Troy Stephens, a coworker of mine on the Cocoa frameworks team, come up, and he's going to show a little app called Cocoa Shuffle.

Now, in iTunes, there's a lovely feature called Party Shuffle, which is kind of this never-ending play list. And we thought that using the new Cocoa Scripting Bridge that let's us talk to iTunes, we would write a small application that more visually demonstrates what songs are coming up in your shuffle. So let's take a look, Troy.

So this is showing us essentially what is currently playing is in the front. And then what's going on is in the back. And I think we need some sound. But that's okay. It's an animation talk after all. We can just imagine the sound. You know, we'll just put it away. I think everybody believes that the Foo Fighters know how to sing.

And we'll get back here. And, of course, we can advance along. And as we do, the new item pops up on the top. And we get a new first song. And let's do it in slow motion. You can look at the pop at the top. Because we're going to show you how to do that. Where it pops in opacity, springs back, following a path along.

Of course, at this point I was going say, boy, that's loud Todd -- or Troy -- would you please pause it? And when we pause, we're able to use a background filter to blur. And again, this all being done with standard NSViews. Those are image views. This is just an NSView with a box and a text field in it. And we're adding animation to it. So let's unpause. And in fact, we've also added tool tips to each item, because from the album you might not know exactly what the song is that's coming up, and contextual menus.

Let's try one of those contextual menus. There we go. And again, it's as easy as setting the tool tip and setting the menu on a standard NSImage view. Now we might like this pattern, but we might want another path to follow. So we added a few presets. But then we figured, you know what, sometimes the presets aren't what you want. You may just want to edit the path yourself.

( Cheering )

And so we add a little Bezier path editor in here. And of course, it's all live, it's all advancing right from iTunes. You see it moving in the background there. And that's a little bit of what we can do with animation in Cocoa. Thank you very much, Troy.

( Applause )

I would also like to thank Kevin Perry, our intern who did a lot of work on that demo over the last week-and-a-half or so. All right, so we hear a lot about animation. What I want to do is kind of frame things in terms of what are the different use case scenarios. Who are the major players as you're thinking about adding animation to your Cocoa app. So we're going to be talking primarily about things happening in AppKit. Specifically NSViews and some animation API that we've added.

And then underneath AppKit is this wonderful graphics framework, Core Animation. And out of all of Core Animation the things we're going be talking and referencing today are layers, as well as animations which help us define custom animations. So let's focus first on NSView, which is not new to the party of Leopard. We've had it for quite a while. And NSView provides a lot of functionality. It has all of the Cocoa controls are NSView subclass, or NSControl subclasses.

Accessibility support, printing, complex event handling, dealing with the responder change, drawing the focus rings, handling full keyboard navigation, dealing with drag and drop. We saw tool tips and contextual menus, cursor reps, tracking reps. There is a lot of interface that's part of NSView. A lot of the interactive experience that you want to maintain. You want to take advantage of that. You don't want to write your own text field from scratch. It doesn't make a lot of sense. So what we are doing is taking all of these views and making them animatible.

So the second thing we've added -- or the first thing we've added in AppKit, is an animation API. And the first scenario might be just basic common animation. I have a window. I need to resize it, and I want that to animate. I want to move a view from point A to point B. And to do this we don't necessarily even need to bring all of Core Animation into the picture. We can simply use the existing AppKit classes and the new animation API to have some basic animations occur.

However, scenario 2 would be using what we call layer-backed views. We'll talk a little more in a moment. But again, you're using the AppKit API, but behind the scenes we've using the power of Core Animation for all of the drawing, rendering, and animating. As well, you can continue using those AppKit animation APIs just as you had in the first scenario. But now it's bringing all of Core Animation to bear in the background. Scenario 3.

Once we've done these default animations, you may want to do custom animations similar to what we saw in that Cocoa Shuffle demonstration. And in this case, you would be using in addition to the AppKit APIs, you would also be using CAAnimation and its friends, its subclasses, in the Core Animation framework to help define those animations.

And there's a fourth scenario. Which is sometimes you may just want to take one NSView and then do all of your animating down in Core Animation. Of these four scenarios, the first three we'll be talking about in this session. The next session will be focused a great deal on the fourth scenario.

Okay. So as we talk about animations -- and let's get to getting things done -- we're going to first talk about some fundamentals. And then we'll get into custom animations. So the fundamentals. In general, animation is fairly straight forward. Objects have properties. We change the value of the property, and we want that object to then change gradually over time, rather than jumping to the new value.

Now in Cocoa, we have accessor methods we have been using for quite a long while to set new property values. So we don't want setFrame to suddenly start moving things around where developers have not been expecting that previously. So we needed a mechanism for setting a new property value, as well as triggering an animation.

And we use what we call the Animator. And here's that half a line of code I was talking about. So Views and Windows have animators, instead of talking directly to the view or directly to the window and telling it to set its frame, for instance. Instead you talk to the Animator and tell it to set the frame.

That will trigger the animation as well as set that value in the view that it's a proxy for. Now these animators are very handy. You can take one and you can hand it in to any API that would normally take the original object. And any message that isn't animated will just pass it through directly to the viewer window.

So with that half line of code you can actually get a great deal done. For all animatible properties, there are already built-in default animations. There are linear animations going from one value to another. They all have a default duration of a quarter second, so they're nice and snappy.

And by default, they're all grouped into one event loop cycle. So in the course of an event you happen to move or change a few different items, they won't start and stop at various different times. They will all be synchronized to the event cycle. And this is all happening with that half a line of code.

Now you might -- though -- want to change some items. And one that you may want to change specifically is the duration. And we've introduced a new class in Leopard called the NSAnimationContext. And essentially, we begin a context or beginning a grouping and end a grouping. Anything within there will be performed at the same time.

And we can also use that context to set the duration. And in fact this is a very handy way to get that slow motion effect when you hold the shift key down. So you can wow people with the slow-mo kind of feature. And we'll show you how to do that in just a couple of minutes.

So I want to just emphasize that the Animator and the animation context -- they're general additions to Cocoa for animating. So regardless of how you're rendering the content, for the basic geometry of Views and Windows, as well as the Window's alphaValue, you can use just Animator and the animation context and get lovely results. However, we do want to take advantage of that Core Animation underneath us. So let's talk a little bit about that.

Core Animation layers are at the core of Core Animation. They are analogous to views, the rectangular areas. They have a hierarchy or a tree of sub layers. They're buffering their context per layer. We can do all sorts of nice visual effects, like applying filters, like the blur filter you saw a little earlier, transitions, shadows, and masking, combining context types. So we want to use these layer things.

In AppKit, we call using a layer a layer -- to back a view, a layer-backed view. So here I have stylized segmented control and an image view and the little blue is just representing that they're part of AppKit; they're AppKit views. And when I'm making a layer-backed view, essentially what I am doing is literally creating these layers in the Core Animation context underneath the Core Animation framework underneath. And then the content, instead of being drawn where it typically is for a view, it is now drawn into the layer and cached there.

And so we call these layer-backed views. It gives us those per-view content buffering. In addition, some of the more -- some of the visual effects, or all of the visual effects of Core Animation come into play. So in addition to the content buffering, we also can apply Core Image effects. Like here we applied a glass filter to the image. We changed the alpha value of the segmented control. And we can apply them and just have them sit, or we can animate them. So in this case we're just slowly coming back.

Core Animation gives us asynchronous animation happening on another thread. As well as we pick up the ability to do transition animations when we're switching subviews, and we can combine different content types. So there's a lot that we can pick up from an NSView if it is layer-backed. So how do we make this happen? We call this line of code.

[view setWantsLayer: YES]; And it really didn't strike -- I've been working with this API -- and it really didn't strike me until I was sitting in the Mac OS X State of the Union yesterday and Bertrand, and all they're talking about, you know, going on at the Ope GL layer and all the work they've been doing down there, and the work they've been doing in the Core Animation layer, and all the work that's been going on -- and the full magnitude didn't strike me that there's all this work going on and for me to get that to happen with my view hierarchy, I basically have one line of code where I say, yeah, I want that. And I was like, that's kind of amazing.

And in fact, if we really don't want to write that one of code we also do have a check box in InterfaceBuilder.

( Laughter )

Which puts us back down to a half line of code. Great. So as sometimes happens, that one little flag has big effects.

So what happens when we do that? Check that off? A lot's going on underneath even though we just made a little tweak. So AppKit is mirroring that entire view subtree into a tree of layers. However, from your standpoint as the creator of a view, -drawRect is still being called when drawing needs to be done.

You still use setNeedsDisplay, and it passes -- does the appropriate thing in the Core Animation framework to make sure that that layer that's backing your view does the right thing. And view properties are basically as you change them they're sent down to the layer as layer properties. And then if there are non-layer properties that we've made animatible, AppKit will handle that animation.

This last bullet point, rather than trying to explain it, let's just talk about it, looking at a picture. So we have a view hierarchy. And that WantsLayer very much expresses -- not necessarily that your preference is going to be respected or not respected in this sense When I say setWantaLayer on any one particular view, that view and all of its subviews in the view hierarchy are backed by a layer. And this is true, then, if say higher up in the hierarchy somebody wanted a layer.

Then from that point on down the tree. There it is. We would see backed by layer. However, if saying that first view decided, no, I no longer want to be backed by a layer, it's already part of a hierarchy that does want a layer. So it retains its layered backing.

Now another nice addition to InterfaceBuilder is that when you're looking at the animations tab for any selected item it will show you the entire view hierarchy, and it will show you if anywhere in the view hierarchy in Interface Builder somebody wants a layer. And I think that's a very handy feature.

Okay, I wanted to bring up one other point about layered backing. Which is that it certainly is wonderful and extraordinarily powerful. But if I have a preference paying with check boxes and stuff and it doesn't usually animate very much, it can be quite overkill to make every single thing layer-backed, because we're caching all of that content, right? In video memory.

And so it can be a very nice strategy if you have typically boring views that occasionally do something exciting and animate, to toggle layer-backed mode. So turn it on and they all get backed by a layer. Have the animation occur, change the animation using the Animator. And then turn layer-backed mode off. So that those resources can get reclaimed.

All right. There we go. I also wanted to point out that as a -- what's the word I'm looking for -- as a side effect -- not even a side effect, asa direct result of being layer-backed, NSViews pick up some new visual properties. alphaValue, shadow, as well as the ability to apply content -- excuse me -- Core Image filters to the content as well as the background in a compositing filter. In addition, you can set all of these up in InterfaceBuilder. Okay. I'm going to bring Troy back up, and we're going to demo using default animations.

Everybody likes this Shuffle. Okay. So the first thing we have here, it's a very simple application, and I believe if this is not available already as sample code, it should be very shortly after the session. It's a simple Cocoa application, and we're just going to first move this NSImageView the old fashioned way using setFrameOrgin.

And it jumps from spot to spot. We can even jump it back. And now let's animate it. Because that is pretty jumpy. So take a look at the code. And in the spot where we do that, moveView, the imageView setFrameOrigin we're going to -- instead of talking to the view directly, add that half line of code and talk to the Animator. Then we'll recompile. And now we've added animation.

( Applause )

Now if we switch to the medium size, I have different size views here. And then we'll try large. Go back to medium. You'll notice that we're resizing the window as we go. And we're also, I believe, getting a cross-data effect. Let's try it with the shift key down.

Ah. We were not getting a cross-fade effect because we were not wanting a layer. When you run into a situation where you're not seeing the animation that you're expecting, because it does happen, the first thing to check is, is it because I forget to make myself layer backed? Now that we do want to layer, we're getting that lovely cross-data effect. We try it with the shift key so that we get that slow-mo effect.

And so we saw the line of code that we wanted to layer. Now let's take a look at the line of code that is both changing the size of the window and the line of code. that is doing the switching of views. So back in Xcode in switchView Most of the code is just figuring out what the new and the old view are based on what was clicked, figuring out the new frame.

But then the core of the code is there. We begin an ending animation context grouping. We only need to do this because we want to implement this shift key slow-mo effect. We do that in two lines of code where we check for the shift key. And if so, we bump the duration up to a second. And then the core of the work is we tell the contentView to replace its subview, the old view with the new view. But instead of talking directly to the view, we talk to its Animator.

Similarly, when we resize the frame of the window we don't talk to the window directly. We just talk to its Animator. And so in that little method we're able to get that very common effect that we see with the animated resize and the subview swapping. Thank you very much, Troy.

(Applause)

  • So the point -
  • or a point I would like to make at this point is that yes, it's a line of code and half a line of code. Really, when it comes to building user interfaces in general, but animated user interfaces in particular, a lot of the work -
  • a lot of the time is spent deciding what you want to do. And what we're trying to do with the API is make it such that it's not the API that is the thing that you have to spend the time on.

It's really working on the usability and making sure that it's an effect that looks nice and that people would want to see over and over again. With this line-and-a-half of code you can get a tremendous amount done in your application. However, sometimes we would like to do custom animations. So let's talk about that a little bit.

So the two things we're going to talk about next are, first, defining custom animations, and then how do we set these animations. We're going to look at a few examples that are kind of little chunks of the things we've seen already so far. So defining animations. We use an expressive set of classes from the Core Animation framework.

Rather than reinventing a new set of animation description classes, we're using the wonderful set that Core Animation has added. And we'll go through each of these in a moment or two. But then once we have created an animation, how do we set it? And it's a very -- well, I'll tell you. First, you create the animation.

The next thing we do is add it to a dictionary, the key in that dictionary is -- or the key in that dictionary is the name of the property that you want this animation to be triggered for. So, in this case, if frameOrigin was set, that animation would be triggered. And then finally we add that dictionary to the views and -- we set that dictionary as the views animations. Now let's take a look at it in code. Create the animation. In this case, a basic animation. Create a dictionary.

In this case, with one animation, one key frameOrigin. And then set that dictionary on the view or window. After we've done that, at any point in the future, somebody talks to that view, or that view's Animator and sets the frameOrigin. That key is going to match up with the key in the dictionary, find that animation that we have added, and it will execute that custom animation rather than the default. We'll see this pattern a lot.

So in dealing with setting up these custom animations, Core Animation classes -- these are the concrete classes, or subclasses of CAAnimation that we'll be dealing with, as well as a MediaTimingFunction to be able to mix up or change up the timing on things. BasicAnimation goes from one value to another.

Keyframe. We can use a path similar to what we did in the Shuffle. Or we can go from one value to another. A Group allows us to group a bunch of animations together. And finally, a Transition as we move between subviews to define visual effects. All right. Let's take a look at a little animation.

And let's take a look at it in slow motion. This is animation along the path using a single keyframe animation. So how do we do this? We use the CAKeyframeAnimation class. We create one. We create a CGPath to describe the path that will be followed. We set the path in the animation.

And then we release the path. I would like to point out that in this case you'll notice that we're just making an animation. We're not tying it at the moment to any particular key or property name. And then once we create it, we're going to set it. Again, we make that dictionary.

We hand in that custom animation. We do it for the key, in this case frameOrigin And then set it in the animations dictionary on the view. Then at any point going through the Animator, when that frameOrigin is set, our custom animation will be triggered. Now let's look at a more complex one. That pop animation and there are two things happening here. We'll play it in slow-mo. There's the opacity going from zero to 1, as well as the size going from zero to larger than the end result, and then popping back.

So to put this together we end up using an AnimationGroup. And in this case we're doing a basic animation, which is the alphaValue going from zero to 1. And we're doing a KeyframeAnimation that scales the frame up and then back a little. Then we're grouping them all together so that they all happen at the same time.

So that's what's going on with the opacity or the alphaValue going from zero to 1. And then more complex is the Keyframe animation, where we're starting at a particular rect, we're popping up to a size, and that's taking 80 percent of the animation. And then the remaining 20 percent is shrinking back down.

So creating the basic animation is very, very simple. Create the basic animation. Now in this case the basic animation and the keyframe animation are inside of a bigger animation. So we need to specify what property this animation is actually effecting. So we use animationWithKeyPath. And this will be effecting the alphaValue. And then we set the from value and the to value.

The keyframe's a bit longer. Then we create it. We can also call setKeyPath to do so after we create it. We create the values in array of -- in this case rectangles that we're going to set as the frame. And by default, those keyframes will happen at equal times along the period or along the animation. But we want them to happen slightly different times. So we will provide a set of times or an array of times between zero and 1 that map to the rectangles for the keyframes.

So we've created those two animations. Now the animation group -- we create the group. We set the animations. It's just an array that goes into the group. And then as we might imagine, we create the ever-popular animations dictionary. We set the dictionary. And now, in this case, we're setting in the dictionary the key alpha. Whenever the alpha value of that view happens to be set, this animation will take place.

The final custom piece we'll look at are transitions. And this happens when subviews change. That was a -- a basic, built-in Core Animation transition. We can also use any of the transitions that are provided in Core Image. This is the photocopying transition. We'll take a look at doing both of those. It's just loving photocopying, isn't it? There we go. So a built-in Core Animation transition. We make the transition. And we set its type and subtype. And those are -- there are a number defining Core Animation. And then from there it's that same old story.

Put it in the dictionary with the particular key. In this case subviews. Set it in the enclosingView, right? Because it's the one whose subviews are changing that needs to have this animation set. And then any time you change the subviews of that particular view using the Animator, it's going to use this particular transition.

Now, if we want to use a Core Image transition, the only difference here is that we use -- we create a Core Image transition filter and set it how we'd like. And then when we create the Core Animation transition animation, we set the filter, and then do all the same things.

So at least for me the -- what I see when I'm doing custom animations is that it is very much deciding what it is you that want to happen, and then those expressive classes make it very simple to tweak what's going on and kind of play with what's going on, and also just not get in your way.

It's a fairly straight-forward methodology. Now what if you want to create some of your own animatible properties? Before we talk about that I just want to point out that NSView and NSWindow do have a lot of built-in animatible properties. So it may very well be that the thing you're thinking you might need to customize already exists. So keep that in mind. And then also to really talk about customize -- or making your own properties, we need a little bit more formal discussion of the API that we've added in Leopard.

That Animator that we've been talking to, and that animations dictionary, the ability to set it and then retrieve it from a view or a window, are actually part of another protocol. The NSAnimatiblePropertyContainer protocol. Essentially, it's possible to be adopted by any object that has properties that could be animated. Now we're familiar with the first three, the Animator. We've been talking to him the whole time. Animations, getting and setting them. That dictionary to define custom animations. Let's talk about those last two.

And so how are these animations triggered? You talk to the Animator and then it looks for an animation. So that animation for key method, you don't call it. The framework calls it to retrieve the right animation for a particular key. And the first thing it will do is look in a custom animation, or that animations dictionary if one is set on the object.

If it's not set on the object it will call that classes +defaultAnimationForKey to try to find an animation. And in fact, that's how all of the default framework animations show up. And so when -animationForKey is called after you've talked to the Animator, we'll first call that animations method to get whatever dictionary may have been set. If none is set or if there's no value in there for that particular key, it will go on to ask the class for the default animation for that particular key.

So that said, implementing a custom property is largely a two-step process. First, define a custom property. It needs to be KVC compliant, KVC setter method. And also important to note that the setter method should trigger needing display, or should tell the view that it needs to redisplay itself. And then second, provide a default animation for that property by overriding +defaultAnimationForKey.

Now once this is done, you can specify custom animations and set them for that key in an animations dictionary. You can treat it pretty much like any other animatible property. And AppKit for these properties will be able to automatically, with a basic animation, interpret basic scalar types. So let's look at an example. Here's the KVC-Compliant setter method.

Important thing to note is the self setNeedsDisplay: YES, so we can redraw itself as it's animated. And then overriding +defaultAnimationForKey. And so all that's happening here is that if the key coming in is our custom property, we'll return some default animation. And again, a basic animation for any scalar type is perfectly fine. Otherwise, we'll just let the superclass return whatever the defaultAnimationForKey is.

Okay. Let's talk about mixing content types. So in the past if you have had, say, an NSOpenGLView and you've tried to put Cocoa controls as subviews, that's something that hasn't been directly possible. We've had to do some workarounds, such as having child windows as overlays, that sort of thing. With a layer-backed view we're able to now mix and match these content types in a way we've really never been able to do before.

So there are two ways we can go about doing this. There's an easy approach, which is that you create the view, an NSView, set that it wants a layer, and then create a Core Animation layer of the appropriate content type. And then we just say set layer, and hand in that type for that view. And then that view will be displaying that particular layer with that particular content. But we can also add subviews as we've always done.

However, if we have an NSOpenGLView it's even easier. We can just create an NSOpenGLView. Turn on layer backing. And that's it. We can then just add sub iews, Cocoa controls, Cocoa widgets to that OpenGLView as a -- as subviews. Just like any other view. And to demonstrate this I would like to bring Troy out.

Okay. So we have here is a rotating earth. It's an OpenGL, NSOpenGLView. It is currently not layer-backed. We have a little checkbox up top. We can spin it, we can do all sorts of stuff. But once we make it layer backed, what we've done is we've animated in an NSBox that is holding Cocoa controls, and these are subviews of the NSOpenGLView.

They're not a parent or child window, they're not some other done overlay. Just a simple item. And then as we adjust the items -- like, let's do the roll. Maybe the camera distance a little. We're effecting that OpenGLView. I'll turn on the wire frame. You can't have OpenGL without a wire frame.

Okay. And no wire frame. And we can also, of course, since these are layer backed apply a Core Image filter in this case. We'll do that glass effect. We seem to like the glass effect. But, of course, if we get rid of the layers by hitting that checkbox, go back to the way we were. Those layers get collected up in the background, they're gone. And let's turn them back on because -- there we go.

Thank you, Troy.

( Applause )

So the other thing that I actually did want to mention is that all of the demos, as well as those animation movies, and hopefully, even Cocoa Shuffle we'd like to get to you as sample code. Some of that will be available this week at the show, and then some of it might take a little while for us to get it out to you. But our intent is to get everything you've seen here out as sample source code.

Now let's just talk -- close up with a few usage tips. Some behavioral nuances. Because when we check that little checkbox we really are rendering the content of a view in a very different way that we have been in the past. So there are a few little nuances.

One of which is that setNeedsDisplay -- you want to make sure that you're very specific about setting needing display or invalidating portions of your view that actually need to be invalidated, and not possibly assuming that because somebody somewhere else in the view hierarchy above you is invalidating, that you're going to get automatically redrawn, even if you haven't asked to be. So be very specify about your setNeedsDisplay.

Another thing to note is that in layer-backed mode, when things move from point A to point B as far as AppKit is concerned, as soon as the animation starts that item is already at its new location. It's a visual treatment that it's moving along. So it's a good idea, one, to turn off or disable, I should say, controls as they're moving so that users don't try to hit them. Because AppKit thinks they're already here.

And finally, layer content is drawn axis-aligned essentially into a buffer. And then that whole buffer is composited in. So as we rotate stuff that looks very nice, but it's also the case that some things that you draw might not look pixel for pixel exactly like the way you draw -- or how we draw right now.

Some performance tips. The first is to avoid redrawing. So things that are not going to change very often, isolate those so that we can cache them and keep them cached. And design by compositing. Applying effects. Rather than redrawing, sometimes the Core Image effect can change -- make something look like its state has changed rather than redrawing the whole thing. And finally, optimate -- optimize that backing store. If you're drawing something this big, don't have a view that's that big and waste a lot of backing store.

So learning more. There's a good deal of the documentation about this. Draft documentation for taking a look at the custom animations. There's the Core Animation headers. Of course, the Leopard AppKit Release Notes. I love the AppKit Release Notes. And then, of course, the sample code that we will be getting to you and some of which should be already available. For more information, of course, there's the website and Deric Horn.

Some take-home points. We really do want these wonderful, lavish animated applications that just have an amazing user experience. But we don't want you to have to completely rearchitect all of your user interfaces to do that What we've done is we've added a small set of API and the ability to access the vast power of Core Animation using standard views and controls. And so we want you to keep designing those great user interfaces. Let us help you do so. And yeah -- we're going to love seeing what you come up with.

( Applause )

And from time to time, in the past they've let me sing. So in the past we have done little songs, or we've done fun songs about model view controller, modelling man, the now somewhat obsolete Cocoa memory management song, Hold Me, Use Me, Release Me.

( Laughter )

- And well, this year -- we -- well, let's just put it this way. I guess sometimes in a person's life they get a feeling deep down that's just so strong that really the only way -- the only way -- you can properly express it is with an up-tempo country western love song.

( Laughter )

And so we'd like to do that for you. Am I ready? Yeah. Right now.

( Music )

  • Singing: I love you -
  • I love view -
  • thinking back on all the things that we've been through. -
  • sometimes I take for granted all those many things you do -
  • so let me take this moment just to say that I love view -
  • NSView, they say opposites attract and so I guess it makes some sense -
  • well, I am not big on parties, but you love handling events -
  • I can't draw Tippy the Turtle, no, nor Pete the Pirate too -
  • but once you lock your focus there's no drawing you can't do -
  • I love view -
  • I love view -
  • and all the subclasses in your retinue -
  • look it up -
  • sometimes I take for granted all those many things you do, let me count the reasons why I say that I love view -
  • Well, you've got buttons and sliders, split view dividers, you never sent a rumor in Apple Insider, handling the drag drops, printing with the can't stop, tool tips, -isFlipped makes you do the flip-flop, handling the menus -
  • -
  • well, back that up a little bit. I forget to tell you all a little earlier that, well, this is a Beta version of the song. Now, let me tell you, it's feature-complete mind you, but I won't have the words memorized till October.

( Laughter )

- Singing: Let's slow this down a little bit. Well -- you've got buttons and sliders, split view dividers, you never sent a rumor in Apple Insider, handling the drag drop, creating like you can't stop, tool tips this, makes you do the flip-flop, menus in the context, cursor and tracking rects -- you draw the focus ring when the user selects, device independence, responder chain descendants, and accessibility too -- I love view -- I love view -- it's a simple love, not much hullabaloo -- I once sent a greeting card by Maya Angelou, the words were mighty flowery, but the gist was I love view -- well, I don't like to say you're easy, I regard you with respect, but it's easy to start drawing, I just implement -drawRect: And then when something changes I just say -setNeeds Display:, you record what needs a date and then redraw it as you may -- well, on that keyboard over yonder there might be a typing sound -- if you are the first responder, you'll then message with -keyDown: -- as for handling a mouse that's been running around your -bounds, I can build a better mousetrap with -mouseUp, -mouseDragged -mouseDown -- I love view -- I love view -- that's why I have your API as a tattoo -- you've added lots of features, 'specially since 10.2 -- I'm running out of places to display that I want you -- well, oh, that Core Animation has a reputation of turning a head or two -- it's so dang good, stick it under the hood of every layer-backed NSView -- I love view -- I love view -- let me tell you one thing more just entre new, I might merge with other classes, but in the end I'm true -- 'cause you won't be drawing a damn thing if you ain't got NSView -- I love view!

( Applause )

Thank you, Gordy.fd Stay up here.

I'm going introduce you -- Gordy!

- Thanks.

( Applause )

- Thank you very much. I also did want to introduce the break points which -- not yet. This is Gordie Freedman on guitar. And Victor Alexander on keyboard.

( Applause )

  • I always call him the best slide advance man in the business. Thank you. Now to --
  • That was fantastic, James.
  • Oh, take that down.
  • We'll look for you on iTunes.
  • Do we have time for Q&A?
  • Yeah.
  • Excellent.
  • I think we have about 15 minutes for Q&A.

- Perfect.

( Laughter )

  • We can do another song. No, have we rehearsed another song? Oh dear. Let's do Hold me, Use me, Release me. ( Cheering ) >> Yeah. But we'll do it quick. Encore. Unless you want some Q&A?
  • Group: No!

- If you do there is always the Cocoa Labs Wednesday and Thursday.

( Music )

  • This is in G. Actually, you play, I'll sing. That's what happened on the first song anyway.
  • Singing: Hold me, use me, then release me -
  • hold me, use me, then release me -
  • there we go. When you play, yeah, go around again. Yes, we rehearsed this thoroughly. One more time. There you go. -
  • when you were locking it, you must dispose of this, yes, and if you should copy, release so your code is not sloppy, do I have to explain -
  • if you explicitly retain then release me, yes, release me, oh release me, oh -
  • hold me, use me, oh, oh, oh, release me -
  • hold me, use me, then release me -
  • darling, if you don't want me any more, please, please just let me know. I've been sitting out here just waiting, just waiting to hear from you. We've had some good times, and I want you to know my accessor methods are wide open for business, baby.

But you know, I understand if you don't need me any more -- if you don't need me any more than just please, please just send me a message. A simple message -- a simple message to let me know -- then release me, yes, release me, release me -- oh -- go into one of those middle parts -- if you == we'll go around again -- uh, yeah.

Okay, I got it now -- here we go -- yes, if you garbage collect me, can't be bothered to personally reject me, send your bookkeeping clerk to do your dirty work, and release me, yes, release me, oh release me, oh -- Everybody! Hold me, use me, then release me -- one more time, hold me, use me, then release -- me -- oh oh oh oh. That'll work. Thank you.

( Applause )