Awaitable Managed Animation classes for WinRT (Part 4)

So far in this post series, I showed how to use code and the new async patterns of WinRT to simplify the animation of elements. As an example, I used opacity, showing how you can code your animation dynamically.

In this post, I’ll show how to move elements about, use translations on them etc. The download link at the bottom of the post contains the sample app and the library used to do the animations.

Let’s make it pop!

First off, let’s change how the squares we had in the previous post appear. Instead of fading them in slowly, let’s make them pop.

That’s usually achieved in XAML by either using projection and making the objects “far” down on the page (projecting the distance on the Z axis) or by simply scaling the element using a ScaleTransform or a CompositeTransform. Since WinRT has a bunch of bugs with the projection transformation, we’ll use the scale one.

The code will be very similar to the staggered fade in we did in the previous blog post. It’s located in the PopPage page. First off, we set up the UI elements much like we did in the previous post. But instead of setting opacity to 0 to start off, we’ll set up the scale to 0. Note that EnsureRenderTransform() is simply an extension method that makes sure the relevant transform class is set on the element.

var transform = control.EnsureRenderTransform<CompositeTransform>();
transform.ScaleY = transform.ScaleX = 0;

 

Now, for our staggered animation of scaling the elements:

private async Task PopAnimationAsync()
{
TimeSpan duration = TimeSpan.FromSeconds(1);
List<Task> tasks = new List<Task>();
foreach (var item in canvas.Children.OfType<FrameworkElement>())
{
tasks.Add(new ScaleTransformManagedAnimation(1, duration).Activate(item));
await Task.Delay(300);
}

await Task.WhenAll(tasks.ToArray());
}

So far, this code is very similar to the opacity animation code, but it uses the ScaleTransformManagedAnimation class to do the animation – we scale the animation to 1 to see the object at it’s full size.

Only problem is… This doesn’t really POP! It just grows and gets to the size… Mundane. Boring. Vanilla. Pedestrian.

What we need is an easing function! Most managed animation classes can take an easing function (or two) as arguments. So let’s do that (showing only the changed line – the one that activates the animation):

tasks.Add(new ScaleTransformManagedAnimation(1, duration, ManagedAnimation.Elastic1Out).Activate(item));

Pop!! The animation has this satisfying quality to it now where the elements “pop” into existence one after another. You can play with the timing and easing function to get to exactly what you want.

As you can see, we simply added another argument to the constructor – ManagedAnimation.Elastic1Out. This makes the Storyboard use the elastic function to calculate the animation. You can pass in any easing function you want – the ManagedAnimation class comes with some predefined ones that seem to be pleasing for certain cases:

public static readonly EasingFunctionBase DefaultOut = new QuadraticEase() { EasingMode = EasingMode.EaseOut };
public static readonly EasingFunctionBase DefaultIn = new QuadraticEase() { EasingMode = EasingMode.EaseIn };
public static readonly EasingFunctionBase DefaultInOut = new QuadraticEase() { EasingMode = EasingMode.EaseInOut };
public static readonly EasingFunctionBase Elastic1Out = new ElasticEase() { EasingMode = EasingMode.EaseOut, Oscillations = 1, Springiness = 3 };
public static readonly EasingFunctionBase Elastic1In = new ElasticEase() { EasingMode = EasingMode.EaseIn, Oscillations = 1, Springiness = 3 };
public static readonly EasingFunctionBase Elastic3Out = new ElasticEase() { EasingMode = EasingMode.EaseOut, Oscillations = 3, Springiness = 3 };
public static readonly EasingFunctionBase Elastic3In = new ElasticEase() { EasingMode = EasingMode.EaseIn, Oscillations = 3, Springiness = 3 };
public static readonly EasingFunctionBase Bounce1Out = new BounceEase() { EasingMode = EasingMode.EaseOut, Bounces = 1, Bounciness = 3 };
public static readonly EasingFunctionBase Bounce1In = new BounceEase() { EasingMode = EasingMode.EaseIn, Bounces = 1, Bounciness = 3 };

 

I want to move it move it!

Elements don’t need to stay in place. You can move elements around your application by using animations. For example, let’s stay that instead our POP! animation, we want the elements to “rise” up one after another from the bottom of the screen and “settle”. Nothing easier! We will use the CanvasMoveManagedAnimation class to do that!

private async Task RiseToTheOccasionAsync(double top)
{
foreach (var item in canvas.Children.OfType<FrameworkElement>())
{
Canvas.SetTop(item, canvas.ActualHeight);
}

TimeSpan duration = TimeSpan.FromSeconds(1);
List<Task> tasks = new List<Task>();
foreach (var item in canvas.Children.OfType<FrameworkElement>())
{
tasks.Add(new CanvasMoveManagedAnimation(Canvas.GetLeft(item), top, duration, ManagedAnimation.Elastic1Out, ManagedAnimation.Elastic1Out).Activate(item));
await Task.Delay(300);
}

await Task.WhenAll(tasks.ToArray());
}

As you can see, the gist of it is very similar to our previous examples.  However, we are using the CanvasMoveManagedAnimation class instead and are telling the element where to go to.

Note that if, during that animation, we were to tell the element to go somewhere else by using the CanvasMoveManagedAnimation class, it would stop where it was at the time of the call, and animate to the new location. As a developer, you need not worry about what it’s doing now in most cases.

Why did you use Canvas.SetTop/Left and not Translation?

This is a matter of preference – since I placed the elements on a canvas, it’s very easy to go and use absolute positioning to play with them. I could just as easily used translations.

One interesting bit about using Canvas positioning to animate your elements around (where applicable of course) is that you can then animate a translation on top of it to make a combined movement.

Other animations supported

Here are the interesting animations present in the library:

  • TranslateTransformManagedAnimation: Does translation animation (as just discussed).
  • SizeManagedAnimation: Animates the Width and Height of an element.
  • ProjectionPropertyManagedAnimation: Animates the various projection properties.
  • FillColorManagedAnimation: Animates the Color property of the Brush applied to a shape.
  • CompositeTransformManagedAnimation: Animates any of the properties of the CompositeTransform on an element.
  •  

    The fun part is that adding your own managed animation classes is very easy. Each one is a couple of lines of code – mostly boiler plate for storing constructor arguments and creating a storyboard.

    The library also contains a couple of other classes for more advanced animations. Specifically, the CanvasCircleMoveManagedAnimation, CanvasSpiralMoveManagedAnimation and CircleGenerator can be used to generate complex movement animations on a canvas (they are needed mostly because WinRT does not support Point path animation).

    What’s next?

    I may do a post in the near future about the more advanced classes. I may also do one on more advanced interruptible interactions that make use of these classes.

    Download

    You can download the full source code here.

    Advertisements
    This entry was posted in Animation, Dev, Windows8. Bookmark the permalink.

    Leave a Reply

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out / Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out / Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out / Change )

    Google+ photo

    You are commenting using your Google+ account. Log Out / Change )

    Connecting to %s