Animations par images clés et animations de fonctions d’accélération

Les animations par images clés linéaires, les animations par images clés avec une valeur KeySpline ou les animations de fonctions d’accélération constituent trois techniques différentes pour pratiquement le même scénario : créer une animation de table de montage séquentiel qui est un peu plus complexe et dont le comportement est non linéaire d’un état de départ à un état de fin.

Prérequis

Lisez au préalable la rubrique Animations de table de montage séquentiel. Cette rubrique s’appuie sur les concepts d’animation expliqués dans la rubrique Animations de table de montage séquentiel mais n’y reviendra pas. Par exemple, la rubrique Animations de table de montage séquentiel décrit comment cibler les animations, les tables de montage en tant que ressources, les valeurs de la propriété Timeline telles que Duration, FillBehavior, etc.

Animation par images clés

Les animations par images clés autorisent plusieurs valeurs cibles pouvant être atteintes à divers points de la chronologie. En d’autres termes, chaque image clé peut spécifier une valeur intermédiaire différente, et la dernière image clé atteinte est la valeur d’animation finale. En précisant plusieurs valeurs à animer, il vous est alors possible d’effectuer des animations plus complexes. Les animations par images clés utilisent également différentes logiques d’interpolation, qui sont mises en œuvre en tant que sous-classe KeyFrame différente par type d’animation. Chaque type d’animation par images clés utilise notamment une variation Discrete, Linear, Spline et Easing de sa classe KeyFrame pour spécifier ses images clés. Par exemple, pour spécifier une animation qui cible un élément Double et utilise des images clés, vous pouvez déclarer des images clés avec DiscreteDoubleKeyFrame, LinearDoubleKeyFrame, SplineDoubleKeyFrame et EasingDoubleKeyFrame. Vous pouvez utiliser n’importe lequel de ces types ou tous ces types dans une collection KeyFrames unique pour changer l’interpolation chaque fois qu’une nouvelle image clé est atteinte.

Concernant le comportement de l’interpolation, chaque image clé contrôle l’interpolation jusqu’à ce que son temps KeyTime soit atteint. Sa Value est atteinte en même temps que ce temps. S’il y a d’autres images clés après cette valeur, la valeur devient la valeur de départ de l’image clé suivante dans la séquence.

Au début de l’animation, si aucune image clé avec un KeyTime dont la valeur est 0:0:0 existe, la valeur de départ est la valeur non animée de la propriété. Cela est similaire à la façon dont une animation From/To/By agit s’il n’y a pas de From.

La durée d’une animation par images clés est implicitement la durée égale à la valeur KeyTime la plus élevée définie dans une de ses images clés. Vous pouvez définir un élément Duration explicite si vous voulez, mais veillez à ce que sa valeur ne soit pas inférieure à celle d’un élément KeyTime dans vos images clés ou vous risquez de couper une partie de l’animation.

En plus de l’élément Duration, vous pouvez définir toutes les propriétés Timeline sur une animation par images clés, comme vous le feriez avec une animation From/To/By, car les classes de l’animation par images clés dérivent également de Timeline. Ces règles sont les suivantes :

  • AutoReverse : une fois la dernière image clé atteinte, les images sont répétées dans l’ordre inverse à partir de la fin. Cela double la durée apparente de l’animation.
  • BeginTime : retarde le début de l’animation. La chronologie des valeurs KeyTime dans les images ne commence à compter que lorsque le BeginTime est atteint, il n’y a donc aucun risque de couper des images.
  • FillBehavior : contrôle ce qui se passe lorsque la dernière image clé est atteinte. FillBehavior n’a aucun effet sur les images clés intermédiaires.
  • RepeatBehavior :
    • Si définie sur Forever, les images clés et leur chronologie se répètent indéfiniment.
    • Si définie sur un nombre d’itérations, la chronologie se répète autant de fois que ce nombre d’itérations.
    • Si la valeur est Durée, l’chronologie se répète jusqu’à ce que cette heure soit atteinte. Cela risque de tronquer l’animation au cours de la séquence d’images clés, s’il ne s’agit pas d’un facteur entier de la durée implicite de la chronologie.
  • SpeedRatio (peu utilisée)

Images clés linéaires

Les images clés linéaires produisent une interpolation linaire simple de la valeur jusqu’à ce que le KeyTime de l’image soit atteint. Ce comportement d’interpolation est le plus similaire aux animations From/To/By les plus simples décrites dans la rubrique Animations de table de montage séquentiel.

Voici comment utiliser une animation par images clés pour modifier la hauteur du rendu d’un rectangle, à l’aide d’images clés linéaires. Cet exemple exécute une animation où la hauteur du rectangle augmente légèrement et de façon linéaire pendant les 4 premières secondes, puis elle augmente rapidement à la dernière seconde pour atteindre le double de la hauteur de départ.

<StackPanel>
    <StackPanel.Resources>
        <Storyboard x:Name="myStoryboard">
            <DoubleAnimationUsingKeyFrames
              Storyboard.TargetName="myRectangle"
              Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
                <LinearDoubleKeyFrame Value="1" KeyTime="0:0:0"/>
                <LinearDoubleKeyFrame Value="1.2" KeyTime="0:0:4"/>
                <LinearDoubleKeyFrame Value="2" KeyTime="0:0:5"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </StackPanel.Resources>
</StackPanel>

Images clés discrètes

Les images clés discrètes n’utilisent aucune interpolation. Lorsqu’un KeyTime est atteint, la nouvelle Value est appliquée. En fonction de la propriété d’interface utilisateur qui est animée, cela produit souvent une animation qui semble « sauter ». Il s’agit du comportement esthétique voulu. Vous pouvez réduire les sauts apparents en augmentant le nombre d’images clés que vous déclarez, mais si vous recherchez une animation fluide, utilisez de préférence des images clés linéaires ou Spline.

Notes

Les images clés discrètes sont le seul moyen d’animer une valeur qui n’est pas de type Double, Point et Color, avec un DiscreteObjectKeyFrame. Nous reviendrons sur ce point plus loin dans cette rubrique.

Images clés Spline

Une trame clé spline crée une transition de variable entre les valeurs en fonction de la valeur de la propriété KeySpline . Cette propriété précise les premier et dernier points de contrôle d’une courbe de Bézier qui décrit l’accélération de l’animation. Fondamentalement, un KeySpline définit une relation fonction-sur-temps où le graphe fonction-temps est la forme de cette courbe de Bézier. Vous spécifiez généralement une valeur KeySpline dans une chaîne d’attributs xaml abrégée qui a quatre valeurs Double séparées par des espaces ou des virgules. Ces valeurs sont des paires X,Y pour deux points de contrôle de la courbe de Bézier. X correspond au temps et Y est le modificateur de fonction de la valeur. Chaque valeur doit toujours être comprise entre 0 et 1. Sans modification des points de contrôle définis par KeySpline, la ligne droite de 0,0 à 1,1 est la représentation de la fonction dans le temps pour une interpolation linéaire. Vos points de contrôle modifient la forme de la courbe et par conséquent le comportement de la fonction dans le temps pour l’animation de spline. Un graphique est probablement le meilleur moyen de le représenter visuellement. Vous pouvez exécuter l’exemple de visualiseur de courbe clé Silverlight dans un navigateur pour voir comment les points de contrôle modifient la courbe et comment une animation exemple s’exécute lorsqu’elle est utilisée en tant que valeur KeySpline.

L’exemple suivant montre trois images clés différentes appliquées à une animation, la dernière étant une animation de courbe clé pour une valeur Double (SplineDoubleKeyFrame). Notez la chaîne 0.6,0.0 0.9,0.00 appliquée pour KeySpline. Cela produit une courbe où l’animation semble s’exécuter d’abord lentement, puis atteint rapidement la valeur juste avant que le KeyTime soit atteint.

<Storyboard x:Name="myStoryboard">
    <!-- Animate the TranslateTransform's X property
        from 0 to 350, then 50,
        then 200 over 10 seconds. -->
    <DoubleAnimationUsingKeyFrames
        Storyboard.TargetName="MyAnimatedTranslateTransform"
        Storyboard.TargetProperty="X"
        Duration="0:0:10" EnableDependentAnimation="True">

        <!-- Using a LinearDoubleKeyFrame, the rectangle moves 
            steadily from its starting position to 500 over 
            the first 3 seconds.  -->
        <LinearDoubleKeyFrame Value="500" KeyTime="0:0:3"/>

        <!-- Using a DiscreteDoubleKeyFrame, the rectangle suddenly 
            appears at 400 after the fourth second of the animation. -->
        <DiscreteDoubleKeyFrame Value="400" KeyTime="0:0:4"/>

        <!-- Using a SplineDoubleKeyFrame, the rectangle moves 
            back to its starting point. The
            animation starts out slowly at first and then speeds up. 
            This KeyFrame ends after the 6th second. -->
        <SplineDoubleKeyFrame KeySpline="0.6,0.0 0.9,0.00" Value="0" KeyTime="0:0:6"/>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

Images clés d’accélération

Une trame clé d’accélération est une trame clé dans laquelle l’interpolation est appliquée, et la fonction au fil du temps de l’interpolation est contrôlée par plusieurs formules mathématiques prédéfinies. En fait, vous pouvez produire le même résultat avec une image clé spline que pour certains des types de fonctions d’accélération, mais il existe également certaines fonctions d’accélération, telles que BackEase, que vous ne pouvez pas reproduire avec une spline.

Pour appliquer une fonction d’accélération à une image clé d’accélération, vous devez définir la propriété EasingFunction en tant qu’élément de propriété dans le balisage XAML de cette image clé. Pour la valeur, spécifiez un élément objet pour l’un des types de fonction d’accélération.

Cet exemple applique un CubicEase puis un BounceEase en tant qu’images clés successives à un DoubleAnimation pour créer un effet de rebond.

<Storyboard x:Name="myStoryboard">
    <DoubleAnimationUsingKeyFrames Duration="0:0:10"
        Storyboard.TargetProperty="Height"
        Storyboard.TargetName="myEllipse">

        <!-- This keyframe animates the ellipse up to the crest 
            where it slows down and stops. -->
        <EasingDoubleKeyFrame Value="-300" KeyTime="00:00:02">
            <EasingDoubleKeyFrame.EasingFunction>
                <CubicEase/>
            </EasingDoubleKeyFrame.EasingFunction>
        </EasingDoubleKeyFrame>

        <!-- This keyframe animates the ellipse back down and makes
            it bounce. -->
        <EasingDoubleKeyFrame Value="0" KeyTime="00:00:06">
            <EasingDoubleKeyFrame.EasingFunction>
                <BounceEase Bounces="5"/>
            </EasingDoubleKeyFrame.EasingFunction>
        </EasingDoubleKeyFrame>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

Il s’agit juste d’un exemple de fonction d’accélération. Nous allons aborder ce sujet plus en détail dans la section suivante.

Fonctions d’accélération

Les fonctions d’accélération permettent d’appliquer des formules mathématiques personnalisées à des animations. Les opérations mathématiques sont souvent plus utiles pour produire des animations qui simulent la physique réelle dans un système de coordonnées 2-D. Par exemple, vous pouvez faire en sorte qu’un objet rebondisse ou se comporte comme s’il était sur un ressort de façon réaliste. Vous pouvez utiliser une image clé ou même des animations From/To/By pour estimer ces effets, mais cela prendrait beaucoup de travail et l’animation serait moins précise que l’utilisation d’une formule mathématique.

Les fonctions d’accélération peuvent être appliquées aux animations de trois manières :

Voici la liste des fonctions d’accélération :

  • BackEase : rétracte le mouvement d’une animation légèrement avant qu’elle ne commence à s’animer dans le chemin indiqué.
  • BounceEase : crée un effet rebond.
  • CircleEase : crée une animation qui accélère ou décélère à l’aide d’une fonction circulaire.
  • CubicEase : crée une animation qui accélère ou décélère à l’aide de la formule f(t) = t3.
  • ElasticEase : génère une animation qui évoque un ressort oscillant jusqu’à son arrêt complet.
  • ExponentialEase : génère une animation qui accélère ou décélère d’après une formule exponentielle.
  • PowerEase : crée une animation qui accélère ou décélère à l’aide de la formule f(t) = tp où p est égal à la propriété Power .
  • QuadraticEase : crée une animation qui accélère ou décélère à l’aide de la formule f(t) = t2.
  • QuarticEase : crée une animation qui accélère ou décélère à l’aide de la formule f(t) = t4.
  • QuinticEase : créez une animation qui accélère ou décélère à l’aide de la formule f(t) = t5.
  • SineEase : génère une animation qui accélère ou décélère d’après une formule s’appuyant sur une fonction sinus.

Certaines des fonctions d’accélération ont des propriétés qui leur sont propres. Par exemple, BounceEase a deux propriétés Bounces et Bounciness qui modifient le comportement de la fonction dans le temps de cette fonction BounceEase. Les autres fonctions d’accélération telles que CubicEase n’ont pas d’autres propriétés que la propriété EasingMode que toutes les fonctions d’accélération partagent et produisent toujours le même comportement de fonction au fil du temps.

Certaines de ces fonctions d’accélération se chevauchent quelque peu, en fonction de la manière dont vous définissez les propriétés des fonctions d’accélération qui ont des propriétés. Par exemple, QuadraticEase est exactement la même qu’un PowerEase avec une puissance égale à 2. Et CircleEase est fondamentalement une valeur exponentielle par défaut.

La fonction d’accélération BackEase est unique, car elle peut changer la valeur en dehors de la plage normale définie par From/To ou des valeurs d’images clés. Il démarre l’animation en modifiant la valeur dans la direction opposée comme on peut s’y attendre à partir d’un comportement De/à normal, retourne à la valeur De ou de démarrage, puis exécute l’animation comme d’habitude.

Dans un exemple précédent, nous vous avons montré comment déclarer une fonction d’accélération pour une animation par images clés. Cet exemple suivant applique une fonction d’accélération à une animation From/To/By .

<StackPanel x:Name="LayoutRoot" Background="White">
    <StackPanel.Resources>
        <Storyboard x:Name="myStoryboard">
            <DoubleAnimation From="30" To="200" Duration="00:00:3" 
                Storyboard.TargetName="myRectangle" 
                Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
                <DoubleAnimation.EasingFunction>
                    <BounceEase Bounces="2" EasingMode="EaseOut" 
                                Bounciness="2"/>
                </DoubleAnimation.EasingFunction>
            </DoubleAnimation>
        </Storyboard>
    </StackPanel.Resources>
    <Rectangle x:Name="myRectangle" Fill="Blue" Width="200" Height="30"/>
</StackPanel>

Lorsqu’une fonction d’accélération est appliquée à une animation From/To/By , elle modifie les caractéristiques de la fonction au fil du temps de la façon dont la valeur interpole entre les valeurs From et To sur la durée de l’animation. Sans fonction d’accélération, l’interpolation serait linéaire.

Animations de valeur d’objet discrètes

Un type d’animation mérite une mention spéciale, car c’est la seule façon d’appliquer une valeur animée à des propriétés qui ne sont pas de type Double, Point ou Couleur. Il s’agit de l’animation d’image clé ObjectAnimationUsingKeyFrames. Créer une animation à l’aide de valeurs Object est différent, car il n’y a aucune possibilité d’interpoler les valeurs entre les images. Lorsque le KeyTime de l’image est atteint, la valeur animée est immédiatement définie avec la valeur spécifiée dans la propriété Value de l’image clé. Étant donné qu’aucune interpolation n’est possible, vous ne pouvez utiliser qu’une seule image clé dans la collection d’images clés ObjectAnimationUsingKeyFrames : DiscreteObjectKeyFrame.

La Value d’un élément DiscreteObjectKeyFrame est souvent définie à l’aide de la syntaxe de l’élément de propriété, car la valeur de l’objet que vous essayez de définir n’est souvent pas exprimable en tant que chaîne pour remplir Value dans la syntaxe d’attribut. Vous pouvez cependant utiliser la syntaxe d’attribut si vous utilisez une référence telle que StaticResource.

Un objet ObjectAnimationUsingKeyFrames est utilisé dans les modèles par défaut lorsqu’une propriété de modèle fait référence à une ressource Brush . Ces ressources sont des objets SolidColorBrush, et pas simplement une valeur Color. D’autre part, elles utilisent des ressources qui sont définies comme des thèmes du système (ThemeDictionaries). Elles peuvent être attribuées directement à une valeur de type Brush telle que la propriété TextBlock.Foreground et elles n’ont pas besoin de recourir au ciblage indirect. Mais étant donné qu’un élément SolidColorBrush n’est pas une propriété Double, Point ou Color, vous devez utiliser un élément ObjectAnimationUsingKeyFrames pour utiliser la ressource.

<Style x:Key="TextButtonStyle" TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid Background="Transparent">
                    <TextBlock x:Name="Text"
                        Text="{TemplateBinding Content}"/>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="PointerOver">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationPointerOverForegroundThemeBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationPressedForegroundThemeBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
...
                       </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Vous pouvez également utiliser ObjectAnimationUsingKeyFrames pour animer des propriétés qui utilisent une valeur d’énumération. Voici un autre exemple de style nommé tiré des modèles Windows Runtime par défaut. Notez comment elle définit la propriété Visibility qui prend une constante d’énumération Visibility . Dans ce cas, vous pouvez définir la valeur à l’aide de la syntaxe d’attribut. Vous avez uniquement besoin du nom non qualifié de la constante d’une énumération pour définir une propriété avec une valeur d’énumération, par exemple « Collapsed ».

<Style x:Key="BackButtonStyle" TargetType="Button">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="Button">
          <Grid x:Name="RootGrid">
            <VisualStateManager.VisualStateGroups>
              <VisualStateGroup x:Name="CommonStates">
              <VisualState x:Name="Normal"/>
...           <VisualState x:Name="Disabled">
                <Storyboard>
                  <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Visibility">
                    <DiscreteObjectKeyFrame Value="Collapsed" KeyTime="0"/>
                  </ObjectAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
            </VisualStateGroup>
...
          </VisualStateManager.VisualStateGroups>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Vous pouvez utiliser plusieurs DiscreteObjectKeyFrame pour un jeu de trames ObjectAnimationUsingKeyFrames . Il peut s’agir d’un moyen intéressant de créer une animation « diaporama » en animant la valeur de Image.Source, comme exemple de scénario pour lequel plusieurs valeurs d’objet peuvent être utiles.