(X) Hide this
    • Login
    • Join
      • Say No Bots Generate New Image
        By clicking 'Register' you accept the terms of use .

Windows 8 Metro: Enforce fluidness with animations and transitions

(5 votes)
Andrea Boschin
>
Andrea Boschin
Joined Nov 17, 2009
Articles:   91
Comments:   9
More Articles
0 comments   /   posted on Sep 11, 2012
Categories:   Windows 8

Animations and mostly transitions are something that may change drastically how your application looks to the end user. This is true twice in a touch enabled application where the usual strategies for giving feedback to the user, about its interaction with UI elements, are not really effective.

Highlighting a button when it is hovered and clicked, changing the color of a link, and other things we are use, are tailored to the mouse pointer, but when fingers is on the scene, the application need a more powerful feedback that involves animations. Extensively speaking animations pervades the Windows 8 applications not limiting itself to UI feedback but also applying beautiful effects that make the interface much more fluid and give it a compelling appearance.

From the developer point of view animations are usually something of hard, just because they bring almost an additional “dimension” to the screens that is the time. Dealing with animations in a classic desktop application is almost impossible but also in a WPF or Silverlight application it may be cause of headaches. Windows 8 metro-style applications comes instead with a number of predefined animations that make the life easy like a breeze.

About Transitions…

Since animations are in XAML from the first beta of WPF, metro brings a new concept on the scene, the transitions. At the first sight it may appear that transitions are simply another way to call animations but is is not so. Transitions are something of an higher level in metro, they use animations to apply a set of standardized actions/effects to elements, and the Visual Tree directly supports them adding a number of properties to different kind of objects.

Transitions property: Almost every visual element in XAML has a Transitions property (it comes from UIElement class) and it is used to apply the transitions directly to the element itself.
ChildrenTransitions property: This property apply to all kind of Panel and is used to give a transitions to all the child elements of the panel.
ItemContainerTransitions property: This property is exposed by the ItemsControl and affect the generated items because it is applied to the container of each element.
ContentTransitions property: This property comes with the ContentControl and is used to apply the transition to the content of an element.

All these properties are collections but they accept only an instance of the TransitionCollection class. Most of them raises an exception if you try to add directly a set of transitions, as you are probably use with WPF and Silverlight collections. There is a wide set of predefined transitions you can use in various scenario. You need some training to use them, but at the end you will be aware that transitions apply to actions, so static elements simply does not even enforce transitions. Here is a list of the available transitions:

AddDeleteThemeTransition: applied when you add or remove items from a collection
ContentThemeTransition: applied when you change the content of a control
EdgeUIThemeTransition: applied when an item appear or disappear by adding to a collection, it slides the new element by right, left, tob or bottom
EntranceThemeTransition: applied when an item is added to the UI
PaneThemeTransition: Use to slide in or out a pane. like it does the settings panel
PopupThemeTransition: Used to popup elements when the are added to collections
ReorderThemeTransition: Used to reposition elements in answer to a change of the order of items in a collection
RepositionThemeTransition: Used to move fluidly an element when it changes its position.

Let me try to make an couple of examples; let say you have a StackPanel and a button that adds elements to the StackPanels’s children collection.

   1: <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
   2:     <Grid.RowDefinitions>
   3:         <RowDefinition Height="120"></RowDefinition>
   4:         <RowDefinition Height="*"></RowDefinition>
   5:     </Grid.RowDefinitions>
   6:     <Grid.ColumnDefinitions>
   7:         <ColumnDefinition Width="120"></ColumnDefinition>
   8:         <ColumnDefinition Width="*"></ColumnDefinition>
   9:     </Grid.ColumnDefinitions>
  10:     <Button x:Name="AddButton" Grid.Column="1" Content="Add element" />
  11:     <StackPanel x:Name="Stack" Grid.Column="1" Grid.Row="1" />
  12: </Grid>

Then you add some code to the codebehind to add a button to the stack every time the user clicks on the AddButton. To mazimize the effect the new element is added to the top of the stack so you need to move element to the bottom every time. Also you handle the click of each button and remove it.

   1: private Button CreateElement()
   2: {
   3:     Button button = new Button
   4:     {
   5:         Content = "click me",
   6:         Style = this.Resources["SampleRect"] as Style
   7:     };
   8:  
   9:     button.Click += ItemButton_Click;
  10:  
  11:     return button;
  12: }
  13:  
  14: private void ItemButton_Click(object sender, RoutedEventArgs e)
  15: {
  16:     this.Stack.Children.Remove((Button)sender);
  17: }

If you run the application now you will see elements adding and removing as usual, like this is a normal WPF application. Elements simply are in one position at a given time and are in another position one moment after. Given that every element has the same content the final appearance is that they are added at the tail of the stack and not at the top; we can do better here. Now returns to the XAML and add the following to the StackPanel

   1: <StackPanel.ChildrenTransitions>
   2:     <TransitionCollection>
   3:         <AddDeleteThemeTransition />
   4:     </TransitionCollection>
   5: </StackPanel.ChildrenTransitions>

Running the example now, you’ll see something changed: Elements appear with a fade animation and existing buttons slide down with a beautiful transition. That’s great if you think at the minimum effort you need for it. But we can do even better adding a RepositionThemeTransition:

   1: <StackPanel.ChildrenTransitions>
   2:     <TransitionCollection>
   3:         <AddDeleteThemeTransition />
   4:         <RepositionThemeTransition />
   5:     </TransitionCollection>
   6: </StackPanel.ChildrenTransitions>

Now elements slide down with an elastic behavior, that confer an effective fluidity to the interface. It seems like the first element push down the second and then everyone push down the following to make room for the new item at the top. Beautiful. Now you can experiment exchanging the AddDeleteThemeTransition with other kind of transitions: As an example try to replace it with this:

   1: <EdgeUIThemeTransition Edge="Left" />

Now the new added element comes from the left side, but also when the item is removed it goes away to the left, from where it came. This behavior can be achieved also when elements are added by databinding. Here is a slightly complex example that involves a GridView:

   1: <GridView x:Name="TestGrid" 
   2:           HorizontalAlignment="Center" VerticalAlignment="Center"
   3:           SelectionMode="None" IsItemClickEnabled="True">
   4:     <GridView.ItemsPanel>
   5:         <ItemsPanelTemplate>
   6:             <VariableSizedWrapGrid Orientation="Vertical" MaximumRowsOrColumns="5" />
   7:         </ItemsPanelTemplate>
   8:     </GridView.ItemsPanel>
   9:     <GridView.ItemContainerTransitions>
  10:         <TransitionCollection>
  11:             <EntranceThemeTransition />
  12:             <RepositionThemeTransition />
  13:         </TransitionCollection>
  14:     </GridView.ItemContainerTransitions>
  15:     <GridView.ItemTemplate>
  16:         <DataTemplate>
  17:             <Border Style="{StaticResource SampleRect}">
  18:                 <TextBlock Text="Click me!" Foreground="Black" Padding="10" />
  19:             </Border>
  20:         </DataTemplate>
  21:     </GridView.ItemTemplate>
  22: </GridView>

In this example items are added to an ObservableCollection that is connected to the ItemsSource property. When Items are added they appear with a simple sliding transition but when one element is removed the RepositionThemeTransition move all the elements and reorder them in a beautiful way. Here is the codebehind:

   1:  
   2: public sealed partial class MainPage : Page
   3: {
   4:     public ObservableCollection<int> Items { get; set; }
   5:  
   6:     public MainPage()
   7:     {
   8:         this.InitializeComponent();
   9:         this.Items = new ObservableCollection<int>();
  10:         this.TestGrid.ItemClick += TestGrid_ItemClick;
  11:         this.TestGrid.ItemsSource = this.Items;
  12:         this.Loaded += MainPage_Loaded;
  13:     }
  14:  
  15:     private void MainPage_Loaded(object sender, RoutedEventArgs e)
  16:     {
  17:         for (int i = 0; i < 25; i++)
  18:             this.Items.Add(i);
  19:     }
  20:  
  21:     private void TestGrid_ItemClick(object sender, ItemClickEventArgs e)
  22:     {
  23:         this.Items.Remove((int)e.ClickedItem);
  24:     }
  25: }

…and about Animations

Since transitions are something of and high level, there is cases where you have to rely on animations to achieve a result. Just before falling down to the usual Storyboard & Animation system, metro gives you another level of support made of predefined animations that solve the most common needs.

But when do you need an Animation? The most common need is to emulate the behavior of a button when clicked. If you have to make an area to react to the PointerPress/PointerReleased events, you probably want an animation to give a feedback to the end user. First of all you have to create the animations in XAML:

   1: <Page.Resources>
   2:     <Storyboard x:Name="ButtonPush">
   3:         <PointerDownThemeAnimation TargetName="MyButton" />
   4:     </Storyboard>
   5:     <Storyboard x:Name="ButtonPop">
   6:         <PointerUpThemeAnimation TargetName="MyButton" />
   7:     </Storyboard>
   8: </Page.Resources>
   9:  
  10: <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
  11:     <Border x:Name="MyButton" Style="{StaticResource SampleRect}" 
  12:             Width="100" Height="100"
  13:             PointerPressed="MyButton_PointerPressed"
  14:             PointerReleased="MyButton_PointerReleased">
  15:     </Border>
  16: </Grid>

Then you have to handle the events on the target element to start the right animation when the user interact with it. This is to call the Begin method of the right animation and nothing else. The PointerDownThemeAnimation and PointerUpThemeAnimation automatically handle all the scenario for you:

   1: private void MyButton_PointerPressed(object sender, PointerRoutedEventArgs e)
   2: {
   3:     ButtonPush.Begin();
   4: }
   5:  
   6: private void MyButton_PointerReleased(object sender, PointerRoutedEventArgs e)
   7: {
   8:     ButtonPop.Begin();
   9: }

The drawback of these animations is that you have to create a number of animation, one for each element that have this behavior. It is because you have to create an hard coded reference from the storyboard and the element to animate. To work around this limitation you can create a user control or a templated control that includes the required animations. In this case the best is to use the VisualStateManager that helps to simplify to handle the animations using states:

   1: <UserControl
   2:     x:Class="XPG.Examples.Animations.Appz.MyButton"
   3:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   4:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   5:     xmlns:local="using:XPG.Examples.Animations.Appz"
   6:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   7:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   8:     mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400">
   9:     
  10:     <UserControl.Resources>
  11:         <Style x:Key="SampleRect" TargetType="Border">
  12:             <Setter Property="BorderBrush" Value="Orange"  />
  13:             <Setter Property="BorderThickness" Value="4"  />
  14:             <Setter Property="Background" Value="White"  />
  15:             <Setter Property="Margin" Value="10" />
  16:         </Style>
  17:     </UserControl.Resources>
  18:     
  19:     <Grid>
  20:         <VisualStateManager.VisualStateGroups>
  21:             <VisualStateGroup x:Name="Common">
  22:                 <VisualState x:Name="Normal" />
  23:                 <VisualState x:Name="Pressed">
  24:                     <Storyboard>
  25:                         <PointerDownThemeAnimation TargetName="ButtonElement" />
  26:                     </Storyboard>
  27:                 </VisualState>
  28:             </VisualStateGroup>
  29:         </VisualStateManager.VisualStateGroups>
  30:         <Border x:Name="ButtonElement" Style="{StaticResource SampleRect}" 
  31:                 PointerPressed="ButtonElement_PointerPressed"
  32:                 PointerReleased="ButtonElement_PointerReleased">
  33:         </Border>
  34:     </Grid>
  35:     
  36: </UserControl>

In the codebehind of the UserControl you have only to handle the events and change the state of the control.

   1: private void ButtonElement_PointerPressed(object sender, PointerRoutedEventArgs e)
   2: {
   3:     VisualStateManager.GoToState(this, "Pressed", true);
   4: }
   5:  
   6: private void ButtonElement_PointerReleased(object sender, PointerRoutedEventArgs e)
   7: {
   8:     VisualStateManager.GoToState(this, "Normal", true);
   9: }

Windows 8 gives a wide set of animations you can use to handle a wide set of needs. Almost all the animations goes in a couple to accomplish the forward and backward action:

RepositionThemeAnimation: handle the event of repositioning an element on the UI. With this animation you are in charge to determine the ending position of the element and the offsets where it is moving. Not a simple animation but very effective
FadeInThemeAnimation/FadeOutThemeAnimation: This couple handles the enter/exit of an element using an fade animation
PointerDownThemeAnimation/PointerUpThemeAnimation: As shown in the example these are used to handle a clickable element
PopInThemeAnimation/PopOutThemeAnimation: These animations are useful to apply a popup-style effect
SplitOpenThemeAnimation/SplitCloseThemeAnimation: These animations are useful to apply a split effect
SwipeBackThemeAnimation/SwipeHintThemeAnimation: These animations are useful to apply a swipe effect
DragItemThemeAnimation/DragOverThemeAnimation/DropTargetItemThemeAnimation: These animations handle the need of drag & drop. The first happen when the drag start, the second when the pointer enter the dragged element and the last when the drag ends.

Fastness & Fluidity for free

Given the “fast & fluid” pillar of the metro guidelines, these animations and transitions are a beautiful tool that helps you to effectively embrace it in your applications without wasting a huge amount of time. At the first met they may seems difficult but after a number of try they reveal all their usefulness.


Subscribe

Comments

No comments

Add Comment

Login to comment:
  *      *       

From this series