SDK Anniversary : les connected animations

Il a toujours été fastidieux dans les apps XAML de faire des animations de transition entre deux pages.
Pour animer une image entre deux pages, il fallait modifier le système de navigation pour permettre ces animations.
L'anniversary update apporte un nouveau moyen appelé les "connected animations" qui rend ces animations triviales à réaliser.


ConnectedAnimation.gif

Comment ça fonctionne ?

La classe ConnectedAnimationService permet de passer un élément visuel entre plusieurs pages XAML.
Nous allons coder ensemble un exemple pour comprendre comment cela fonctionne.

Page maître:

 La partie XAML :

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <GridView x:Name="ItemsGridView"
                Loaded="ItemsGridView_Loaded"
                SelectionMode="None"
                IsItemClickEnabled="True"
                ItemClick="ItemsGridView_ItemClick"
                Margin="50"
                ItemsSource="{x:Bind ViewModel.Items}">


        <GridView.ItemTemplate>
            <DataTemplate x:DataType="data:Thumbnail">
                <Border BorderBrush="Black"
                        BorderThickness="1">
                    <Image x:Name="ImageItem"
                            Width="200"
                            Height="200"
                            Margin="2"
                            Stretch="Uniform"
                            Source="{x:Bind ImageUrl}" />
                </Border>
            </DataTemplate>
        </GridView.ItemTemplate>
    </GridView>
</Grid>

 
Dans le code C# nous utiliserons l'animation avec l'objet visuel à animer :

private void ItemsGridView_ItemClick(object sender, ItemClickEventArgs e)
{
    var container = ItemsGridView.ContainerFromItem(e.ClickedItem) as GridViewItem;
    if (container != null)
    {
        var root = (FrameworkElement)container.ContentTemplateRoot;
        //Au click sur la gridView
        //Récupération de l'image que l'on veut animer.
        var image = (UIElement)root.FindName("ImageItem");
        //On prépare l'animation
        ConnectedAnimationService.GetForCurrentView().PrepareToAnimate("Image", image);
    }

    var item = (Thumbnail)e.ClickedItem;
    //On navigue vers la page détail : en passant en paramètre l'url de l'image selectionnée
    Frame.Navigate(typeof(ConnectedAnimationDetail), _navigatedUri = item.ImageUrl);
}


Page de détail :

 Dans la page de détail, nous recevrons l'image à animer :

<Page x:Class="UWPWhatsNew.Views.ConnectedAnimation.ConnectedAnimationDetail"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:UWPWhatsNew.Views.ConnectedAnimation"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">
    <Grid>
        <Image x:Name="_image"
               Margin="50"
               VerticalAlignment="Center"
               HorizontalAlignment="Center" />
    </Grid>
</Page>

Dans le code C# nous recevrons l'image à animer et nous lançons l'animation :

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e)
    //Récupération du paramètre passé lors de la navigation
    _image.Source = new BitmapImage(new Uri((string)e.Parameter));
    //On récupére l'animation ayant comme nom Image.
    var animation = ConnectedAnimationService.GetForCurrentView().GetAnimation("Image");
    if (animation != null)
    {
        _image.Opacity = 0;
        //On lance l'animation uniquement quand l'image est chargée
        _image.ImageOpened += (sender_, e_) =>
        {
            animation.TryStart(_image);
        };
    }
    //On s'abonne à l'évènement back de la page, comme ça l'utilisateur clickera sur back on rejouera l'animation dans l'autre sens
    _systemNavigationManager.BackRequested += ConnectedAnimationDetail_BackRequested;
    _systemNavigationManager.AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
}

Lorsque l'utilisateur clique sur back, on prépare l'animation pour que la page maître puisse jouer l'animation.

private void ConnectedAnimationDetail_BackRequested(object sender, BackRequestedEventArgs e)
{
    if (e.Handled)
    {
        return;
    }
    ConnectedAnimationService.GetForCurrentView().PrepareToAnimate("Image", _image);
    e.Handled = true;
    Frame.GoBack();
}


Au retour sur la page maître:

private void ItemsGridView_Loaded(object sender, RoutedEventArgs e)
{
    if (_navigatedUri != null)
    {
        //récupération de l'animation
        var animation = ConnectedAnimationService.GetForCurrentView().GetAnimation("Image");
        if (animation != null)
        {
            var item =  ViewModel.Items.Where(compare => compare.ImageUrl == _navigatedUri).First();

            //on scroll vers l'item
            ItemsGridView.ScrollIntoView(item, ScrollIntoViewAlignment.Default);
            ItemsGridView.UpdateLayout();

            var container = ItemsGridView.ContainerFromItem(item) as GridViewItem;
            if (container != null)
            {
                var root = (FrameworkElement)container.ContentTemplateRoot;
                var image = (Image)root.FindName("ImageItem");
                image.Opacity = 1;
                //on lance l'animation
                animation.TryStart(image);
            }
            else
            {
                animation.Cancel();
            }
        }

        _navigatedUri = null;
    }
}


Et si tous mes clients ne sont pas sur anniversary update?

Vous pouvez dès à présent ajouter des nouveautés d'anniversary Update. Mais avant d'utiliser la classe ConnectedAnimationService il faudra vérifier si votre client a bien l'API présente. Ci-dessous le code vérification :


private bool HaveConnectedAnimationService()
{
    return ApiInformation.IsTypePresent("Windows.UI.Xaml.Media.Animation.ConnectedAnimationService");
}

//Vérification que l'API est présente.
if(HaveConnectedAnimationService())
{
    var animation = ConnectedAnimationService.GetForCurrentView().GetAnimation("Image");
    ...
}

Pour aller plus loin

Lien vers la doc officielle
Vidéo de BUILD montrant les connected animations
Lien vers le GitHub de démo de MS

Happy coding :)

Photo de profil

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus