Compartir a través de


Animaciones fotograma a fotograma y animaciones con funciones de suavizado

Las animaciones de fotograma clave lineales, las animaciones de fotograma clave con un valor KeySpline o las funciones de aceleración son tres técnicas diferentes para aproximadamente el mismo escenario: crear una animación con guion gráfico que sea un poco más compleja y que use un comportamiento de animación no lineal desde un estado inicial hasta un estado final.

Prerrequisitos

Asegúrese de que ha leído el tema Animaciones con guion gráfico. Este tema se basa en los conceptos de animación que se explicaron en animaciones con guion gráfico y no volverá a pasar por ellos. Por ejemplo, Las animaciones con guion gráfico se utilizan para definir cómo apuntar a animaciones, storyboards como recursos, los valores de la propiedad Timeline como Duration, FillBehavior, y así sucesivamente.

Animación mediante animaciones de fotograma clave

Las animaciones de fotograma clave permiten más de un valor de destino que se alcanza en un punto a lo largo de la escala de tiempo de animación. En otras palabras, cada fotograma clave puede especificar un valor intermedio diferente y el último fotograma clave alcanzado es el valor de animación final. Al especificar varios valores para animar, puede crear animaciones más complejas. Las animaciones de fotogramas clave habilitan el uso de diferentes lógicas de interpolación, cada una de las cuales se implementa como una subclase diferente de KeyFrame por tipo de animación. En concreto, cada tipo de animación de fotograma clave tiene una variación Discrete, Linear, Spline y Easing de su clase KeyFrame para especificar sus fotogramas clave. Por ejemplo, para especificar una animación que se dirige a un Doble y usa fotogramas clave, podría declarar fotogramas clave con DiscreteDoubleKeyFrame, LinearDoubleKeyFrame, SplineDoubleKeyFrame y EasingDoubleKeyFrame. Puede usar cualquiera de estos tipos dentro de una sola colección KeyFrames para cambiar la interpolación cada vez que se alcanza un nuevo fotograma clave.

Para el comportamiento de interpolación, cada fotograma clave controla la interpolación hasta que se alcanza su KeyTime. Su valor se alcanza también en ese momento. Si hay más fotogramas clave más allá, el valor se convierte en el valor inicial del siguiente fotograma clave de una secuencia.

Al principio de la animación, si no existe ningún fotograma clave con KeyTime de "0:0:0", el valor inicial es lo que sea el valor no animado de la propiedad. Esto es similar a la forma en que actúa una animación From/To/By si no hay From.

La duración de una animación de fotograma clave es igual, de manera implícita, al valor KeyTime más alto establecido en cualquiera de sus fotogramas clave. Puede establecer una duración explícita si lo desea, pero tenga cuidado de que no sea menor que KeyTime en sus propios fotogramas clave o cortará parte de la animación.

Además de Duration, puedes establecer todas las propiedades basadas en Cronología en una animación de fotograma clave, tal como puedes hacerlo con una animación From/To/By, ya que las clases de animación de fotograma clave también derivan de Cronología. Estos son:

  • AutoReverse: una vez alcanzado el último fotograma clave, los fotogramas se repiten en orden inverso desde el final. Esto duplica la duración aparente de la animación.
  • BeginTime: retrasa el inicio de la animación. La escala de tiempo de los valores KeyTime de los fotogramas no empieza a contar hasta que se alcanza BeginTime , por lo que no hay ningún riesgo de cortar fotogramas.
  • FillBehavior: controla lo que sucede cuando se alcanza el último fotograma clave. FillBehavior no tiene ningún efecto en ningún fotograma clave intermedio.
  • RepeatBehavior:
    • Si se establece en Forever, los fotogramas clave y su escala de tiempo se repiten infinitamente.
    • Si se establece en un recuento de iteraciones, la línea de tiempo se repite ese número de veces.
    • Si se establece en Duration, la escala de tiempo se repite hasta que se alcanza ese tiempo. Esto podría truncar la animación a mitad de la secuencia de fotogramas clave, si no es un factor entero de la duración implícita de la línea de tiempo.
  • SpeedRatio (no usado habitualmente)

Fotogramas clave lineales

Los fotogramas clave lineales dan como resultado una interpolación lineal simple del valor hasta que se alcanza el KeyTime del fotograma. Este comportamiento de interpolación es el más parecido a las animaciones más simples From/To/By descritas en el tema Animaciones con guion gráfico.

Aquí se muestra cómo usar una animación de fotograma clave para escalar el alto de representación de un rectángulo mediante fotogramas clave lineales. En este ejemplo se ejecuta una animación en la que el alto del rectángulo aumenta ligeramente y linealmente durante los primeros 4 segundos y, a continuación, se escala rápidamente durante el último segundo hasta que el rectángulo sea doble el alto inicial.

<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>

Fotogramas clave discretos

Los fotogramas clave discretos no usan ninguna interpolación en absoluto. Cuando se alcanza KeyTime, el nuevo Valor se aplica de manera directa. Dependiendo de la propiedad de la interfaz de usuario que se anima, esto suele producir una animación que parece "dar un salto". Asegúrate de que este es el comportamiento estético que realmente quieres. Puedes minimizar los saltos aparentes aumentando el número de fotogramas clave que declaras, pero si una animación suave es tu objetivo, podrías estar mejor usando fotogramas clave lineales o spline en su lugar.

Nota:

Los fotogramas clave discretos son la única manera de animar un valor que no es de tipo Double, Point o Color, con un DiscreteObjectKeyFrame. Lo analizaremos con más detalle más adelante en este tema.

Fotogramas clave spline

Un marco clave spline crea una transición variable entre valores según el valor de la propiedad KeySpline . Esta propiedad especifica los puntos de control primero y segundo de una curva Bezier, que describe la aceleración de la animación. Básicamente, una KeySpline define una relación de función a lo largo del tiempo donde el gráfico en tiempo de función es la forma de esa curva Bézier. Normalmente, se especifica un valor KeySpline en una cadena de atributo abreviado XAML que tiene cuatro valores Double separados por espacios o comas. Estos valores son pares "X,Y" para dos puntos de control de la curva Bezier. "X" es la hora y "Y" es el modificador de función para el valor. Cada valor siempre debe estar comprendido entre 0 y 1 ambos inclusive. Sin modificación del punto de control en una keySpline, la línea recta de 0,0 a 1,1 es la representación de una función a lo largo del tiempo para una interpolación lineal. Los puntos de control cambian la forma de esa curva y, por tanto, el comportamiento de la función a lo largo del tiempo en la animación de spline. Es probable que sea mejor ver esto visualmente como un gráfico.

En este ejemplo siguiente se muestran tres fotogramas clave diferentes aplicados a una animación, siendo la última una animación spline clave para un valor Double (SplineDoubleKeyFrame). Observe la cadena "0.6,0.0 0.9,0.00" aplicada a KeySpline. Esto genera una curva en la que la animación parece ejecutarse lentamente al principio, pero luego alcanza rápidamente el valor justo antes de alcanzar KeyTime .

<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>

Suavizado de fotogramas clave

Un fotograma clave de suavizado es un fotograma clave en el que se aplica la interpolación, y la función a lo largo del tiempo de la interpolación está controlada por varias fórmulas matemáticas predefinidas. En realidad, puede obtener resultados muy similares con un fotograma clave de tipo spline como con algunos tipos de funciones de aceleración, pero también hay algunas funciones de aceleración, como BackEase, que no se pueden reproducir con un spline.

Para aplicar una función de suavizado a un fotograma clave de suavizado, estableces la propiedad EasingFunction como un elemento de propiedad en XAML para ese fotograma clave. Para el valor, especifique un elemento de objeto para uno de los tipos de función de aceleración.

En este ejemplo se aplica un CubicEase y, a continuación, un BounceEase como fotogramas clave sucesivos a DoubleAnimation para crear un efecto de rebote.

<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>

Este es solo un ejemplo de función de suavizado. Trataremos más en la sección siguiente.

Funciones de suavizado

Las funciones de suavizado permiten aplicar fórmulas matemáticas personalizadas a las animaciones. Las operaciones matemáticas suelen ser útiles para producir animaciones que simulan la física del mundo real en un sistema de coordenadas 2D. Por ejemplo, puede que desee que un objeto rebote o se comporte de forma realista como si estuviera en un muelle. Podrías usar fotograma clave o incluso animaciones From/To/By para aproximar estos efectos, pero requeriría una gran cantidad de trabajo y la animación sería menos precisa que la utilización de una fórmula matemática.

Las funciones de aceleración se pueden aplicar a animaciones de tres maneras:

Esta es una lista de las funciones de suavizado:

  • BackEase: retira el movimiento de una animación ligeramente antes de empezar a animarse en la ruta indicada.
  • BounceEase: crea un efecto de rebote.
  • CircleEase: crea una animación que acelera o ralentiza mediante una función circular.
  • CubicEase: crea una animación que acelera o ralentiza mediante la fórmula f(t) = t3.
  • ElasticEase: crea una animación similar a un resorte que oscila hacia atrás y hacia delante hasta que llega a descansar.
  • ExponentialEase: crea una animación que acelera o ralentiza mediante una fórmula exponencial.
  • PowerEase: crea una animación que acelera o ralentiza mediante la fórmula f(t) = tp donde p es igual a la propiedad Power .
  • QuadraticEase: crea una animación que acelera o decelera mediante la fórmula f(t) = t2.
  • QuarticEase: crea una animación que acelera o ralentiza mediante la fórmula f(t) = t4.
  • QuinticEase: cree una animación que acelere o decelere mediante la fórmula f(t) = t5.
  • SineEase: crea una animación que acelera o ralentiza mediante una fórmula sine.

Algunas de las funciones de aceleración tienen sus propias propiedades. Por ejemplo, BounceEase tiene dos propiedades Bounces y Bounciness que modifican el comportamiento de función a lo largo del tiempo de ese BounceEase determinado. Otras funciones de aceleración, como CubicEase , no tienen propiedades distintas de la propiedad EasingMode que comparten todas las funciones de aceleración y siempre producen el mismo comportamiento de función a lo largo del tiempo.

Algunas de estas funciones de aceleración presentan cierta superposición, dependiendo de cómo configures las propiedades en aquellas funciones de aceleración que disponen de propiedades. Por ejemplo, QuadraticEase es exactamente igual que PowerEase con Power igual a 2. Y CircleEase es básicamente un valor predeterminado ExponentialEase.

La función de aceleración BackEase es única porque puede modificar el valor fuera del intervalo normal según lo establecido por From/To o los valores de los fotogramas clave. Inicia la animación cambiando el valor en la dirección opuesta como se esperaría de un comportamiento From/To normal, vuelve al valor From o inicial de nuevo y a continuación, ejecuta la animación como es normal.

En un ejemplo anterior, se mostró cómo declarar una función de aceleración para una animación de fotogramas clave. En el siguiente ejemplo se aplica una función de suavizado a una animación 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>

Cuando se aplica una función de suavizado a una animación From/To/By, modifica las características de cambio a lo largo del tiempo de cómo el valor se interpola entre los valores From y To durante la duración de la animación. Sin una función de aceleración, sería una interpolación lineal.

Animaciones de objeto de valor discretas

Un tipo de animación merece una mención especial porque es la única manera de aplicar un valor animado a las propiedades que no son de tipo Double, Point o Color. Esta es la animación de fotograma clave ObjectAnimationUsingKeyFrames. La animación mediante valores object es diferente porque no hay posibilidad de interpolar los valores entre los fotogramas. Cuando se alcanza el KeyTime del fotograma, el valor animado se establece inmediatamente en el Value especificado en el fotograma clave. Dado que no hay interpolación, solo hay un fotograma clave que se usa en la colección de fotogramas clave ObjectAnimationUsingKeyFrames : DiscreteObjectKeyFrame.

El valor de discreteObjectKeyFrame se establece a menudo mediante la sintaxis del elemento de propiedad, ya que el valor del objeto que intenta establecer a menudo no se puede expresar como una cadena para rellenar la sintaxis de atributo Value . Todavía puede usar la sintaxis de atributo si usa una referencia como StaticResource.

Un lugar donde verá un objectAnimationUsingKeyFrames usado en las plantillas predeterminadas es cuando una propiedad de plantilla hace referencia a un recurso Brush . Estos recursos son objetos SolidColorBrush , no solo un valor color y usan recursos definidos como temas del sistema (ThemeDictionaries). Se pueden asignar directamente a un valor de tipo Brush, como TextBlock.Foreground y no es necesario usar el destino indirecto. Pero dado que solidColorBrush no es Double, Point o Color, debe usar objectAnimationUsingKeyFrames para usar el recurso.

<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>

También puede usar ObjectAnimationUsingKeyFrames para animar propiedades que usan un valor de enumeración. Este es otro ejemplo de un estilo con nombre que procede de las plantillas predeterminadas de Windows Runtime. Observe cómo establece la propiedad Visibility que toma una constante de enumeración Visibility . En este caso, puede establecer el valor mediante la sintaxis de atributo. Solo necesita el nombre de constante no calificado de una enumeración para configurar una propiedad con un valor de enumeración, por ejemplo, "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>

Puede usar más de un DiscreteObjectKeyFrame para un ObjectAnimationUsingKeyFrames. Esta podría ser una manera interesante de crear una animación de "presentación con diapositivas" animando el valor de Image.Source, como escenario de ejemplo para donde varios valores de objeto podrían ser útiles.