For the last couple of weeks I’ve been mucking around with dynamic animations in Silverlight 2, and I found them quite tiring and verbose to write. I also found it time consuming to link them together in to a series – to run animation a, then b, then c and so on.
So I decided to do something about it, and this is the result.
High Quality (view in browser and download WMV).
I created a new set of classes collectively called the AnimationChainer. It allows you to quickly create animations using a convenient syntax. You will find creating animations with this set of classes is much nicer than the manual way. These animations can then be easily chained together to create more advanced behavior.
The basic overview of the AnimationChainer is:
- Create groups of animations
- Add groups to a main animation controller
- Groups contain multiple animations
- Animations can be delayed
- Groups can run in serial or parallel mode (run all animations at once etc)
- You can make the manager run all groups at once or again, serially (so run a group, which has 3 animations, then run the next group and so on)
- You can fire callbacks on completion
- After a manager has started animating, you can control behavior if you add more animations to it.
- Cancel animations
Unlike some other animation systems out there already in Silverlight 2, this one uses real Timeline based animations and storyboards. A group becomes a storyboard basically, and the animations are added to it (each one can be cumulatively delayed by more and more).
Important: Before this sample will work, copy the Windows Vista sample images in to AnimationHelper\Images
Note: Press F5 in between each demo to reset the app to the original state:)
The demo has four examples in it:
The first example demonstrates the ability to cut off an executing animation and start a new one. This happens whenever the user moves the mouse. It also shows delayed start for the groups, each letter starts slightly after the one before it.
The second example throws the Windows Vista sample images in to random positions and random rotations on the screen. It does this 10 times for each set of images. This demonstrates serial animations in groups – only one image per group comes out at a time, but parallel groups, i.e. 10 groups send out one image each at a time.
The third example is a wrap panel which uses keyframe animations to “hop” in content.
The fourth example is the same wrap panel, but this time the animations “pop” in. Animated wrap panels are cool! 🙂
These demonstrate only the tip of the iceburg on what is possible with this class.
I don’t get groups and stuff
So what can you do with this? You could make it so that things first zoom in to view, then they might wiggle a little, then zoom out. The Zoom in would be a ScaleY and ScaleX animation, so you would put these in the same group so they would run together. You would put the second part, the wiggle in to another group so you could make it run only after the first animation had completed.
Coding against this class couldn’t be easier.
To create the zoom in animation I spoke of you could do this:
//Set the transform group (you don't have to do this if you element comes from XAML and already has a TransformGroup) TransformGroup tg = new TransformGroup(); element.RenderTransform = tg; //Add a scale transform, and set it to scale X and Y to 0 ScaleTransform st = new ScaleTransform(); tg.Children.Add(st); st.SetValue(ScaleTransform.ScaleXProperty, (double)0); st.SetValue(ScaleTransform.ScaleYProperty, (double)0); //Create the chainer manager to house the animation groups AnimationChainManager cm2 = new AnimationChainManager(true); //true here means that each group will run in serial mode, one after the other. cm2.Add() //Adds a new animation group .DoubleAnimation() //Adds a new DoubleAnimation to the group .Target(st) //Sets the animation target to the ScaleTransform .Property(ScaleTransform.ScaleXProperty) //Sets the Target Dependency Property .Duration(new TimeSpan(0, 0, 0, 0, 100)) //Sets the time span of the animation .From(0) //Sets the starting position of the animation .To(1) //Sets the ending position of the animation .Queue() //Adds this animation to the queue (not required, but best practice) .DoubleAnimation() //Creates a second animation for the other scale axis .Property(ScaleTransform.ScaleYProperty) //Sets the Target Dependency Property. Note we didn't have to set the Target again! .From(0) //Sets the starting point and so on. .To(1) .Queue(); cm2.Begin(false, false); //Start animations with parameters: Don't wait for previous anims to finish, and don't cancel any that are already running
See, easy as! Watch the video to see this in action (download and play with the sample project too).
Supported animation types
The classes support DoubleAnimation, ColorAnimation and PointAnimation. It also supports the key frame based variants of these three types.
List of available commands
- .Serial – Run the animations within the group serially
- .Target – The DependencyObject to animate against
- .Property – The DependencyProperty to animation
- .DoubleAnimation – New DoubleAnimation
- .DoubleAnimationK – New DoubleAnimationUsingKeyFrames
- .PointAnimation – New PointAnimation
- .PointAnimationK – New PointAnimationUsingKeyFrames
- .ColorAnimation – New ColorAnimation
- .ColorAnimationK – New ColorAnimationUsingKeyFrames
- .KeyFrame – Adds a keyframe to the KeyFrame animation. The offset is cumulative (added on to the last offset)
- .Context – Some context to fire back with the completion event and callback
- .From – From value for all animation types
- .To – To value for all animation types
- .Duration – The length of this animation
- .Offset – The offest from the start of the group to start this animation
- .CompleteAction – Action callback
- .Reverse – Replay the animation backwards on completion
- .Queue – Adds the animation to the queue
When adding multiple animations to the same group, you don’t need to keep setting properties like Target and Duration – the system remembers them and does it automatically for you.
The manager can be configured to behave in different ways.
- Play groups sequentially (altered in constructor)
- Toggle cancel groups current playing and start newly added groups
- Toggle wait for current groups to finish before playing newly added groups
- Begin method starts playing the groups
- GroupDelay method allows you to set a group to wait before animating.
How does it work
Basically this set of classes is just a wrapper for the animation classes. Each group is converted in to a StoryBoard when it’s told to run 🙂 Download the code and check it out for yourself.
Another example – keyframes
This sample is from the main project available for download. It makes the elements of the wrap panel jump on to the screen.
cm2.Add() .DoubleAnimationK() //Create the keyframe animation .Target(tt) //Set its target to the TranslateTransform created earlier .Property(TranslateTransform.YProperty) //Tell it to do the YProperty .KeyFrame(-height, new TimeSpan(0, 0, 0, 0, 1)) //Add first keyframe .KeyFrame(-300, new TimeSpan(0, 0, 0, 0, 100)) //Add the second keyframe at 101ms .KeyFrame(0, new TimeSpan(0, 0, 0, 0, 100)) //Add third keyframe, at 201ms (1 + 100 + 100) .Queue() //Add to queue .DoubleAnimationK() //Repeat for other axis .Property(TranslateTransform.XProperty) .KeyFrame(-(width + realLeft), new TimeSpan(0, 0, 0, 0, 0)) .KeyFrame(-300,new TimeSpan(0, 0, 0, 0, 100)) .KeyFrame(0,new TimeSpan(0, 0, 0, 0, 100)) .Queue();