Part 22: Animating the Reel Grid with a Storyboard
The final step will be fun ... we'll animate the reel object on our record audio screen. We want it to rotate as we're recording ... that's a nice visualization of what the app is doing, a nice visual cue to the user that they are in the middle of an important operation with the app.
Our game plan in this lesson:
- We'll create a Storyboard that includes an animation to rotate the Ellipse and the other objects.
- We'll programmatically start and stop the animation
... but first we'll need to learn a little about creating animations on the Windows Phone.
1. Declaratively define the animation
Before we dive too deeply into the topic of animation, I want to discuss it at a high level. Once we're comfortable with how animation works in XAML UI frameworks, we'll have a bit more confidence to apply a specific animation to rotate our reel.
First, its important to realize that XAML controls like the Grid, Button, etc. are defined separately from animation definitions. You can create an animation that is applied to different controls as needed. An animation is associated with a control and then triggered by some event. In our case, we've already defined the Grid and the shapes that will comprise the reel. We'll soon define an animation and associate the two, then we'll write C# code to trigger the animation. Again, we'll do all of this before the end of this lesson.
Animations are made up of a Storyboard object and at least one Animation object.
Let's start with the Animation. First, there are several different types of animation data types. We're using a DoubleAnimation data type because we want to move a property (the Rotation property) from 0.0 to 360.0—the angle of the animation every 4 seconds. In other words, we want the Grid to rotate every 4 seconds. Besides the DoubleAnimation, there's also a ColorAnimation class for animating between two colors, and a PointAnimation for modifying an objects X Y coordinate or its size.
An Animation is basically a timeline combined with a result. The results are determined by the specific Animation class you pick like we just talked about. It's important to know that all Animation classes inherit from a Timeline class which confers properties related to timing of the animation ... the Begin time, allowing you to delay the start of animation, perhaps waiting for other animations on the storyboard to begin or complete, a Duration property that effects how long the animation should take before delivering the desired result—how long should it take for our fade-in effect, in this case. There are also AutoReverse and RepeatBehavior properties, which do what they suggest.
A Storyboard is a collection of one or more Animations. You group the Animations you want triggered by a specific event such as a button click, a loaded event, and so on. The Storyboard allows you to pair an Animation with a target object. The animation is just a definition of what property should be affected, when it should be affected and how long. We have to APPLY that Animation to a target object. In our case, that target object will be the Grid that contains our shapes representing the reel.
Our Storyboard will be simple since we just want one thing to happen—a rotation from 0 to 360 degrees every 4 seconds. Once we're ready to allow the Storyboard to play, we call its Begin() method. It will in turn kick off all it's child Animations and child Storyboards.
There are 4 possible transforms that you can animate as listed and diagrammed on this page:
(I realize that this article is specifically for WPF, but many of the concepts transfer to the Windows Phone API.)
... as well as other attributes you can change with the ColorAnimation and the like. There's a lot more to learn about animations, and for a more complete explanation of animations, I recommend you start here:
Now that you have the basics of StoryBoards and Animations, let's modify the Grid containing the shapes that comprise the reel graphic. You'll recall that the large ellipse and the smaller rectangles and ellipse are all contained in a Grid for layout purposes.
To get them to all move correctly at the same time, it is easier to just animate / rotate the grid (rather than each individual shape):
I'll add a name so I can access it programmatically, and I want to indicate that I want to entire grid and all its children to animate together, as a group, or rather as a composite:
- Add the programmatic name attribute.
- I set the RenderTransform property to CompositeTransform. Essentially, what I'm saying is that I will transform the contents of the Grid as one complete unit. I've not provided the details of HOW I'll transform the grid, just the fact that, for the purpose of performing transformations on the Grid, I want to treat the Grid and its children as a group. I'll define HOW I'll transform the grid in a Storyboard.
Near the top of the RecordAudio.xaml page (beneath the PhoneApplicationPage declaration), I will add a Resources section:
- We're creating a Page-level resource.
- We're creating a Storyboard ... because it's Page-level, we could re-use this in other spots in our page. We'll give the Storyboard a name, "RotateCircle" and once it starts, it's repeat behavior should be "Forever". We'll control start and stop programmatically. I'll access this Storyboard programmatically by it's name in a moment to start / stop it.
- We'll build a DoubleAnimation object. Why DoubleAnimation? As we discussed at the outset, we want to modify the Rotation property (see the Storyboard.Target property) from 0.0 to 360.0, which are numerical (and therefore will require we use the DoubleAnimation). We set the duration of the animation to 4 seconds and so, in 4 seconds, we want to increase the Rotation value starting at 0 and increasing to 360. We set the TargetName, which is the name we gave the Grid containing our reel. The TargetProperty is tricky ... we have to write it this way due to the fact that we're working with a CompositeTransform ... as I mentioned a moment ago, we want to animate the Grid AND ITS CHILDREN. Otherwise, we could simply set the TargetProperty="Rotation".
2. Programmatically start and stop the animation
What comes next is easy now that we've declaratively defined the animation. We'll start and stop the animation based on the state of the ToggleButton:
- While recording, start the animation.
- When finished recording, stop the animation.
If we were to run the application at this point, we would notice an odd behavior while recording:
The reel is not rotating in place, but rather, it is rotating around the page. This is because we didn't define the spot of origin for the transform to take place. Instead of at its default X Y position (0, 0 ... upper left-had corner), we want it to be in the middle (.5, .5), so we'll set the RenderTransformOrigin to that position:
Now when we re-run the app, the reel spins instead of traveling:
3. Deploy to physical Phone Device
Just for fun, I wanted to see this working on my Nokia Lumia 920, so I connected my device to my computer with a USB cable and used the drop-down next to the Run button on the toolbar to select Device:
I was able to run the app, record and save sounds, even hit break points just like I could using the Emulator in Visual Studio. Excellent.
To recap, in this lesson we learned about animation using Storyboard and the relation to Animation classes. We talked about the different types of animations and transforms you can add to your app. Then, we learned how to programmatically trigger the storyboard and how to stop it. We learned about things like how to modify the rotation animation's starting point by changing RenderTransformOrigin attribute. The big takeaway is that if you can imagine it, there's likely a way to accomplish it given the wealth of animation options in XAML and the Windows Phone API.
Now that we've finished our first version of this app, I want to challenge you to add some functionality on your own. I haven't yet added these features myself, and there's no denying that they would require a day or two to research, develop and debug, but here's what I would like you to try and add:
- Figure out how to add images to each item. You'll need to manipulate the data model to accommodate an associated image file, and you'll have to add image files to the project, add an Image control to the DataTemplate, and bind to it. Actually, if you watch the rest of this series you'll get some hints on how to accomplish this because we'll be binding images to tiles (among other things) as we create our second full app.
- Figure out how to delete items. Right now, if you add a custom sound, there's no way to get rid of it. That's an unfortunate limitation. Clint suggests you use a Context Menu from the Windows Phone Toolkit (which we'll learn about that when we work on the next app as well).
- Figure out how to pin sounds to the Start page. That's something I've never tried to implement, but I know there are tutorials out there that can lead you in the right direction.
Are there other features that would make this app cool? Try adding them or share them as challenges to your fellow students in the comments below the video.
Now we have to move on ... we'll begin our second app in the next lesson.