With the introduction of every new Microsoft developer platform comes the challenge of mastering the entire framework in a way that enables the creation of high quality, optimized UI controls that are intuitive to end users. The launch of Microsoft’s latest mobile framework, Windows Phone 7, is no exception. Fortunately, a major portion of Windows Phone development is based entirely on Silverlight, making mobile development easier than ever and jumpstarting the process of mastering the new platform. Rich, interactive applications are going to be the norm on Windows Phone, but new challenges, like optimizing code for battery life and mobile processors, will have to be tackled. Building “good” applications for Windows Phone must be done carefully and with the right tools as there is no room for inefficient code or memory leaks.
One of the ways apps for Windows Phone can deliver richer experiences that imitate the platform is to add motion to interactions. Windows Phone relies heavily on motion, such as animated content transitions, to define the mobile experience. To help app developers quickly add these transitions to any app, Telerik has constructed a rich animation framework optimized for Windows Phone. Building this framework in a way that fully leverages the power of Windows Phone while only sipping battery requires focused engineering, and in this article we’ll examine specific coding techniques that make this possible.
The Animation Framework
While working with XAML storyboards directly is always an option for creating animations in Silverlight, it is much easier to have a set of predefined logical animations that create and update the needed storyboards automatically. This is the purpose of the Telerik animation framework: to simplify animations in Windows Phone 7 (WP7) apps, both in code and XAML.
Without an animation framework, adding a simple “Fade Out” animation to a WP7 app can be done in a number of different ways:
- Option 1: Associate storyboards to specific routed events using event triggers to begin their execution. Unfortunately, this approach is limited to the “Loaded” event only and is discouraged for application development.
- Option 2: Put storyboards directly in the resources of a page and start their execution with code.
- Option 3: Use VisualStateManager and VisualStates to execute animations. This is typically the recommended approach in application development.
Since Option 1 is discouraged, we will not look at code for that approach. Here is what Option 2 might look like in code for adding a “fade out” animation to a button on WP7:
<Button x:Name="AnimationTarget"
Content="Animate" Grid.Row="1"
Click="Animate_Click">
</Button>
<phone:PhoneApplicationPage.Resources>
<Storyboard x:Key="MyStoryboard">
<DoubleAnimation Duration="0:0:.2"
To=".5"
Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="AnimationTarget"/>
</Storyboard>
</phone:PhoneApplicationPage.Resources>
With the above XAML, we also need code to start the storyboard:
private void Animate_Click(object sender,
RoutedEventArgs e)
{
Storyboard storyboard =
this.Resources["MyStoryboard"] as Storyboard;
storyboard.Begin();
}
This solution works, but it is not the preferred coding pattern for XAML, and it is difficult to reuse throughout an app. Option 3, using visual states, is more architecturally proper, but requires quite a bit of code (Listing 1) to achieve the same effect:
And like Option 2, code is still required to go to the specified visual states:
private bool animated;
private void Animate_Click(object sender,
RoutedEventArgs e)
{
if (animated)
{
VisualStateManager.GoToState(
this.AnimationTarget, "NotAnimated",
true);
}
else
{
VisualStateManager.GoToState(
this.AnimationTarget, "Animated", true);
}
this.animated = !this.animated;
}
Except in the case of defining a default style for a control, writing the above XAML for a simple animated transition is enormous overhead. And this is the simplest possible animation! The XAML needed for more complex animations can easily become so large that it would be simply unmaintainable throughout an application.
Telerik’s RadAnimation provides an easy to use animation framework that requires minimal XAML declaration for common animations. Complex animations are also possible thanks to the ability to stack an arbitrary number of animations within an AnimationGroup and apply that Group to a single element. This makes it easy to add rich animations to WP7 apps with minimal code overhead. RadAnimation includes a handful of the most commonly used animations and transitions, and it is available as part of the RadControls for Windows Phone.
Unlike the code heavy “manual” approaches examined previously, adding animation with RadAnimation looks like this in code:
<phone:PhoneApplicationPage.Resources>
<telerikAnimation:MoveAnimation
x:Key="TelerikAnimation" Duration="0:0:.5"
StartPosition="0,0" EndPosition="100,100">
</telerikAnimation:MoveAnimation>
</phone:PhoneApplicationPage.Resources>
In the code, two lines are required to initiate the animation:
private void Animate_Click(object sender,
RoutedEventArgs e)
{
MoveAnimation animation =
this.Resources["TelerikAnimation"] as
MoveAnimation;
AnimationManager.Play(this.AnimationTarget,
animation);
}
In this example, the animation will automatically assign TranslateTransform as a RenderTransform to the animation target and will animate its X and Y properties.
Each RadAnimation also defines the properties that are normally assigned to a Storyboard, such as Duration, SpeedRation, FillBehavior and AutoReverse. When the animations complete, depending on the FillBehavior setting, each RadAnimation will also apply the final values as local to the animated element so that all storyboards may be stopped without losing the animation context.
Continuing with the previous example, the following code enhances the animation with some fade out effects:
The code shows two animations, MoveAnimation and FadeAnimation, grouped by an AnimationGroup. Any number of animations can be grouped. For example, adding a plane projection can create a more dramatic effect (see Listing 2):
When an animation is added to a group, its duration property is bound to the value specified by the AnimationGroup. All other common storyboard properties are automatically inherited from the parent group (if not specified locally). Once defined, the AnimationManager enables easy animation reuse. Simply play any RadAnimation instance on any element. In addition, you can even cancel running animations and perform additional logic upon their completion by providing a Completed handler.
Animated Page Transitions
If you have used a Windows Phone, you would certainly have noticed the animated transitions when navigating through pages and apps. How can these animations be added to any WP7 app? By default, page navigation within a WP7 Silverlight application is done by simply changing the Content of the root visual, typically a PhoneApplicationFrame instance. The common page transition implementation handles the OnNavigatingFrom (called when a page is about to become inactive) and OnNavigatedTo (called when a page has become active), executing storyboards that perform animations either directly on the page or on its child controls. While this approach works, it adds enormous overhead to apply it to more than a few pages (a common page base class helps, but it must be used by all pages).
A more elegant solution is to extend the PhoneApplicationFrame and apply transitions transparently to navigated pages. Being a ContentControl, the OnContentChanged notification of the PhoneApplicationFrame can be handled, and the animation logic can be added there.
While the navigated pages can be directly animated, heavier pages with a lot of content can drain performance. For example, animating a Panorama or Pivot page directly produces some funky results. The performance optimized solution used by RadAnimation is to create snapshots of both pages, hiding the actual content and performing animations on the images rather than the real pages. This allows for creation of smooth and slick transitions without any visual glitches.
Digging into the RadAnimation implementation, you can use the code in Listing 3 to define the control template of the “extended” application frame that simplifies page animations:
Before a new page is navigated, a snapshot of the current content is captured in memory. Then, upon the content change notification, a snapshot of the new content is made. Now, the original content is hidden and two animations are started, one for the old content image and another for the new content image. When both animations are complete, the two snapshot images are hidden and the actual content is displayed again.
Currently a transition is described by a model object named FrameTransition, which is a member of RadApplicationFrame. It exposes InAnimation, OutAnimation, Enabled and other properties that allow you to fine-tune the desired effect. The “In” and “Out” animations are of type RadAnimation and practically any visual effect can be easily achieved by simply specifying the appropriate animation or animation group. The FrameTransition instance also handles the animation start/stop logic, as well as snapshot creation. Each snapshot is a WriteableBitmap instance that is cached on the hardware accelerated Compositor thread, giving RadAnimation, and apps using it, unbeatable performance since a single bitmap can be animated much faster and with minimum performance drain than a fully functional page with content.
Again looking at the internals of RadAnimation, Listing 4 shows how the FrameTransition handles the OnContentChanged notification, delegated by its owning frame:
In the future, RadAnimation will provide a set of predefined animation groups that describe some of the most commonly used transitions on Windows Phone so that apps can quickly enable stunning effects with a single line of code. The Telerik animation framework will also allow these animations to be specified as attached properties to a PhoneApplicationPage, which will enable you to specify different transitions for different pages.
Everything in Windows Phone 7 is content and motion. Telerik is bringing years of Silverlight experience to Windows Phone to make tools that simplify and accelerate app development, with special attention to techniques that optimize performance and battery life. With RadAnimation, Telerik makes it easy to add motion to any Windows Phone 7 app while saving developers time and bloated code. If you are interested in learning more about Telerik UI components for Windows Phone 7, visit www.telerik.com/windows-phone.
<telerikAnimation:AnimationGroup
x:Key="TelerikAnimation" Duration="0:0:.5">
<telerikAnimation:AnimationGroup.Children>
<telerikAnimation:MoveAnimation
StartPosition="0,0"
EndPosition="100,100"/>
<telerikAnimation:FadeAnimation
Direction="Out"
MinOpacity=".5"
MaxOpacity="1"/>
<telerikAnimation:PerspectiveAnimation
Axes="Y"
CenterY="0"
StartAngleY="0"
EndAngleY="60"/>
</telerikAnimation:AnimationGroup.Children>
</telerikAnimation:AnimationGroup>