April 2018

Volume 33 Number 4

[Fluent Design]

Using Fluent: Swipe Gesture Action and Connected Animations

By Lucas Haines | April 2018

Application developers have more and more device types to deal with, from ubiquitous smartphones and traditional desktop and laptop PCs, to large-format touchscreen displays and even emerging virtual and augmented reality platforms like HoloLens. The Fluent Design System is specifically designed and continually evolving to make it is easier for developers to integrate modern features for the mixed device ecosystem. The Fluent features added to the Windows 10 platform in the Fall Creators Update are a powerful case in point, enabling applications to feel natural, no matter on what device they run.

Fluent UI features like light, blur and depth combine to enable compelling and intuitive experiences that allow users to do more. But until recently, challenges remained for users trying get the most out of their devices. With the Windows 10 Fall Creators Update, Fluent adds two features that solve both problems today: Swipe Gesture Actions and Connected Animations.

Swipe Gesture Actions

It comes as no surprise that sales of touchscreen-equipped PCs continue to grow. The question for developers is how to help users do more by enabling interaction models that work both for touchscreen PCs and classic keyboard and mouse.

The answer comes in the form of on-object commanding, which has been around for years via either a right-click or a tap and hold. These tried and true methods are well understood, but with a bit of work you can build in accelerators that leverage the capabilities of the device ecosystem to make them better.

Enter gesture actions, which are great accelerators that work for both touch and keyboard users. Gesture actions are a handy accelerator for contextual commands typically hidden behind a right-click menu or on a separate commanding bar. Other examples of gesture actions include hover buttons, swipe, and keyboard accelerators.

Swipe for commanding isn’t a new concept. The interaction pattern exists on both Google Material Design and Apple iOS. It’s useful for quickly triaging items in a list—for example, deleting photos or e-mails in a scroll—or for revealing the most-used commands in a scenario. The XAML Swipe Control makes it very easy to add this great functionality to your Universal Windows Platform (UWP) apps.

The Swipe control contains two behaviors, Reveal mode and Execute mode:

Reveal mode can display one or more commands associated with a selected item so that a user can select from among them. For instance, if you have a list of messages and you want to quickly enable forwarding, creating a follow up reminder, or scheduling a meeting, reveal mode makes this possible without forcing the user to navigate screens. This can be very powerful for the “on the go” user.

Execute mode completes the command with a simple gesture. The most common and easiest example would be delete. I no longer need this message and want to forget it ever existed. One simple gesture (like a swipe left) and it’s off to the recycling bin. Execute mode doesn’t have to be destructive. Another great example is swipe to save. Say in one column you have a list of customers and when you select one a detail pane appears to the right. After the user makes changes to the form or customer record, he or she simply swipes the item to save the changes. Simple and fast.

However, before I can create the swipe behavior on my list, I like to set up the SymbolIconSource for my application. This provides a really easy way to access icons for your application. Adding the symbols to page.resources allows me to easily add icons where needed later in the code. Regardless of implementing swipe, this is great at making code more readable and taking advantage of IntelliSense in Visual Studio. Here’s the code:

<Page.Resources>
  <SymbolIconSource x:Key="ReplyIcon" Symbol="MailReplyAll" />
  <SymbolIconSource x:Key="PinIcon" Symbol="Pin" />
  <SymbolIconSource x:Key="DeleteIcon" Symbol="Delete" />
</Page.Resources>

With the resources loaded, I can begin to implement the swipe gesture API on an element. List views are an extremely common element to implement swipe gestures, so that’s what I’ll work with, as shown in the code in Figure 1.

Figure 1 Implementing Swipe on a ListView

<ListView x:Name="MainList" Width="400" Height="500">
  <ListView.ItemTemplate>
    <DataTemplate x:DataType="x:String">
      <SwipeControl x:Name="LVSwipeContainer"
                    LeftItems="{StaticResource RevealOptions}"
                    RightItems="{StaticResource ExecuteDelete}">
        <StackPanel Orientation="Vertical" Margin="5">
          <TextBlock Text="{x:Bind}" FontSize="18" />
          <StackPanel Orientation="Horizontal">
            <TextBlock Text="Data Template Font" FontSize="12" />
          </StackPanel>
        </StackPanel>
      </SwipeControl>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

Notice in Figure 1 that I’m using the LeftItems and RightItems property in the SwipeControl API. LeftItems determines what happens when the user swipes left (in this case, RevealOptions) and places the command buttons to the right side.

The directional item references a Static Resource, which is defined in SwipeItems placed in page resources with my icons source. This is where I set the behavior mode to either Reveal or Execute, like so:

<Page.Resources>
  <SwipeItems x:Key="RevealOptions" Mode="Reveal">
    <SwipeItem Text="Reply" IconSource="{StaticResource ReplyIcon}"
      Foreground="White"/>
    <SwipeItem Text="Pin" IconSource="{StaticResource PinIcon}"
      Foreground="White" />
  </SwipeItems>
  <SwipeItems x:Key="ExecuteOptions" Mode="Execute">
    <SwipeItem Text="Delete" IconSource="{StaticResource DeleteIcon}"
      Invoked="SwipeItem_Invoked"
      Background="Red" Foreground="White" />
  </SwipeItems>
</Page.Resources>

Now that I have the UI created and the interaction working, I can use the Invoke property to set up an event handler and process the action. Processing the command when a swipe is performed is done on the SwipeItems declaration in page.resources by setting the Invoked property. Here’s the code for that:

<SwipeItem Text="Delete" IconSource="{StaticResource DeleteIcon}"  
  Invoked="DeleteItem_Invoked"
  Background="Red" Foreground="White" />

Once in the codebehind, you can add your code for handling the command here:

private void DeleteItem_Invoked(SwipeItem sender, 
  SwipeItemInvokedEventArgs args)
{
  int index = myListView.Items.IndexOf(args.SwipeControl.DataContext);
  myListView.Items.RemoveAt(index);
}

Even though the origin of swipe is rooted in touch devices, it works great with track pads and pen. I often find that when I’m working with a device that isn’t touch-enabled that I check for swipe gestures with the track pad. I’m always delighted when I find that it works. By default, Fluent Swipe Gesture actions work with track pads, giving users more ways to quickly complete their tasks and move on. It’s a perfect example of implementing for one input method and benefiting all users.

When thinking of adding swipe to your application, consider if the gesture will conflict with other behaviors in the application. Do you have a FlipView, Hub or Pivot as the main content area in your application? That’s probably not the best place to implement swipe because the interaction patterns are very similar and getting the right balance for users can be difficult.

Swipe is great when the same action needs to be repeated multiple times, but remember that the result of the action needs to be consistent. I can’t think of a worse scenario than having a user who understands that swiping left will favorite an item, only to find on the next screen that the same gesture deletes it. Finally a tip: In my experience, swipe for touch or mouse users is best if the item being swiped is at least 300 pixels wide.

Connected Animations

Today, many apps and Web sites have “jerky” or non sequitur transitions. When an action is taken that requires page navigation, the user is only presented with the new page. There are few—if any—visual cues to provide context or guidance about what to do, where to go or what is new. With connected animations, you can preserve context for the user and increase engagement, such as by animating the clicked item from a list to the target location of the details page. Or you can keep the user’s Avatar visible while they navigate through an application. It’s all about maintaining context and focus.

Adding in connected animations is an incremental process. If you want to implement it for all your page transitions, please don’t let me stop you. But we all have a backlog of work to burn through, so it may be best to be selective and tackle the effort over time. There are two steps required to implement connected animations:

  1. Prepare an animation object on the source page.
  2. Start the animation on the destination page.

Preparing the animation on the source page allows you to set the source object that’s to be animated across the pages. The same image source should be set on the destination page, though you can use a lower-resolution image for the target page. This can reduce the memory footprint of your application. The connected animation will then crossfade between the two images.

The general rule of thumb with connected animations is that animation should start approximately 250 milliseconds between the two steps or else the source element may hang in the view and end up looking weird. With the implicit animation engine shipped in Windows 10, if you prepare an animation but don’t start it within three seconds, the system will dispose of it.

For this scenario I’m going to use ListView with some text and images, using the code provided in Figure 2. Both Listview and Gridview have two methods added specifically for connected animations: PrepareConnectedAnimations and TryStartConnectedAnimationAsync.

Figure 2 Setting Up ListView Collection to Animate

<ListView x:Name="Collection"
                  ItemClick="Collection_ItemClick"
                  ItemsSource="{Binding Source={StaticResource ItemsViewSource}}"
                  IsItemClickEnabled="True"
                  SelectionMode="None"
                  Loaded="Collection_Loaded"
                  Grid.Row="1">
  <ListView.ItemTemplate>
    <DataTemplate x:DataType="local:CustomDataObject">
      <Grid Margin="0,12,0,12">
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="Auto" MinWidth="150" />
          <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <!-- image to be animated-->
        <Image x:Name="ConnectedElement" Source="{x:Bind ImageLocation}"
          MaxHeight="100"
          Stretch="Fill" />
        <StackPanel Margin="12,0,0,0" Grid.Column="1" >
          <TextBlock Text="{x:Bind Title}" HorizontalAlignment="Left"
            Margin="0,0,0,6" />
          <StackPanel Orientation="Horizontal" >
            <TextBlock Text="{x:Bind Popularfor}" />
          </StackPanel>
        </StackPanel>
      </Grid>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

The key element in this list is the x:Name of the image in the DataTemplate. This is the name that I’ll use when I create the ConnectedAnimation and prepare it for the destination page. When an item in the collection is clicked it will navigate to the new page. I’ll prepare the connected animation during the click method. The event handler set on the list Collection_ItemClicked is where I prepare the ConnectedAnimation before navigation. The PrepareConnectedAnimation method expects a unique key, the item, and the name of the element to be animated. In the method I’ve named my animation “ca1,” which will reference on the destination page when the animation is started, as shown in Figure 3.

Figure 3 PrepareConnectedAnimation Method

private void Collection_ItemClick(object sender, 
  ItemClickEventArgs e)
{
  var container = 
    collection.ContainerFromItem(e.ClickedItem) as ListViewItem;
  if (container != null)
  {
    _storeditem = container.Content as CustomDataObject;
  var animation = collection.PrepareConnectedAnimation("ca1", _
    storeditem, "ConnectedElement");
  }
  Frame.Navigate(typeof(DestinationPage), _storeditem);
}

SuppressNavigationTransitionInfo blocks the default page transition animation from playing, and helps prevent it from interfering with the connected animation. Using the OnNavigatedTo method for the destination page, I create a ConnectedAnimation and pass in the unique key I created on the source page (“ca1”). Then I call TryStart and pass in the name of the XAML image element I want to animate to, using this XAML code:

<Image x:Name="detailedIamge" MaxHeight="400" 
  Source="{x:Bind ImageLocation}" />

And this C# code:

ConnectedAnimation imageAnimation =
  ConnectedAnimationService.GetForCurrentView().GetAnimation("ca1");
if (imageAnimation != null)
{
  imageAnimation.TryStart(detailedIamge);
}

This creates the one-way connected animation from the listview to the destination page. I still need to create another connected animation to handle the back navigation scenario. I prepare the connected animation in the OnNavigateFrom override and give it a unique key, “ca2,” as shown in the following code:

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
  base.OnNavigatedFrom(e);
  ConnectedAnimationService.GetForCurrentView().PrepareToAnimate("ca2", detailedIamge);
}

The ca2 animation is started using the collections loaded method declared in the listview template, like so:

private async void Collection_Loaded(object sender, RoutedEventArgs e)
{
  if (_storeditem != null)
  {
    ConnectedAnimation backAnimation =
      ConnectedAnimationService.GetForCurrentView().GetAnimation("ca2");
    if (backAnimation != null)
    {
      await collection.TryStartConnectedAnimationAsync(backAnimation, _
        storeditem, "ConnectedElement");
    }
  }
}

I’m using the async TryStart method called on the listview, to ensure that the listview content is rehydrated before the animation starts.

Typically with lists or dense views of data you have lots of secondary data associated with the item—for example, mail subject, sender, date/time and the like. We can aid the user even further by animating these elements into view. This requires using CoordinatedAnimation, which I can do by using the two-parameter overload for TryStart.

First, I need to create an element on the destination page to show the appropriate content. I’m using a stackpanel with a text block inside and I’ve named the stackpanel CoordinatedPanel, as shown here:

<StackPanel x:Name="CoordinatedPanel" Grid.Column="1"
  VerticalAlignment="Top" Margin="20,0">
<TextBlock Text="{x:Bind HeaderText}" Style="{ThemeResource SubheaderTextBlockStyle}"
  Margin="0,0,0,10" />
</StackPanel>

Then I use the overload for TryStart to reference both the connected animation and the UI element to coordinate with, like so:

ConnectedAnimation imageAnimation =
  ConnectedAnimationService.GetForCurrentView().GetAnimation("ca1");
if (imageAnimation != null)
{
  imageAnimation.TryStart(detailedIamge, new UIElement[] { CoordinatedPanel });
}

This will allow both the connected animation I created and any other animations on the UI to run at the same time, helping the user understand context faster with a more immersive experience.

A quick note: I avoid using connected animations if my UI depends on network requests or any long-running asynchronous operations between preparing and starting the animation. These scenarios will cause a perceived glitch in your application or create delays that detract from the impact of the animation. To compensate for these situations, consider loading assets and images into your application ahead of time.

Wrapping Up

Swipe gesture actions and connected animations are useful resources that can ease interaction, add visual context, and create a compelling and intuitive experience for your end users. In the case of swipe gesture actions, the interaction pattern is easy to implement and adds a new level of efficiency for the user that extends to track pads and pen users. These little interactions can add up when users repeat the same actions over and over again.

Connected animations aid the user by providing visual context when navigating between pages, while at the same time enabling an engaging experience. From a developer standpoint, connected animations can be employed incrementally at key moments in the application. The result: End users enjoy a more cohesive and compelling experience that motivates them to use the application more often.


Lucas Haines works with the XAML Controls team at Microsoft focusing on design and UI solutions for the Fluent Design System. He also worked three years at the Central Windows Design studio, where he helped shape the Fluent platform.

Thanks to the following Microsoft technical experts for reviewing this article: Steven Moyes, Kiki Saintonge
Kiki Saintonge hails from Ellsworth, Maine, and has a passion for video games and especially tooling and UI technologies, leading her to Washington State to learn computer science. A Windows kid at heart, she now works on developing the best controls and experiences for the XAML team at Microsoft.

Steven Moyes is a Microsoft program manager in Redmond, Washington, working on making animations in UWP XAML easier and more powerful. In his free time, you can find him playing video games, reading, or working on personal coding projects.d


Discuss this article in the MSDN Magazine forum