Compartir a través de


Animaciones de fotograma clave y animaciones de función de aceleración

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.

Requisitos previos

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 describen cómo dirigirse a animaciones, guiones gráficos como recursos, los valores de propiedad Timeline, como Duration, FillBehavior, etc.

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 fotograma clave también permiten una lógica de interpolación diferente, que se implementan como una subclase de fotograma clave diferente 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 destinada a double 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 hora KeyTime . Su valor también se alcanza 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 cómo actúa una animación From/To/By si no hay From.

La duración de una animación de fotograma clave es implícitamente la duración igual 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 timeline basadas en una animación de fotograma clave, como puedes con una animación From/To/By, ya que las clases de animación de fotograma clave también derivan de Timeline. Dichos componentes 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 escala de tiempo se repite muchas veces.
    • Si se establece en duration, la escala de tiempo se repite hasta que se alcanza esa hora. Esto podría truncar la parte de animación a través de la secuencia de fotogramas clave, si no es un factor entero de la duración implícita de la escala 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 keyTime del marco. Este comportamiento de interpolación es el más similar al más sencillo de las animaciones 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. Cuando se alcanza keyTime, el nuevo valor se aplica simplemente. Dependiendo de la propiedad de la interfaz de usuario que se está animando, esto suele producir una animación que parece "saltar". 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 y 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 Bezier. 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 con el tiempo para la animación spline. Es probable que sea mejor ver esto visualmente como un gráfico. Puede ejecutar el ejemplo del visualizador key-spline de Silverlight en un explorador para ver cómo los puntos de control modifican la curva y cómo se ejecuta una animación de ejemplo cuando se usa como un valor KeySpline .

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>

Aceleración de fotogramas clave

Un fotograma clave de aceleración 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 se controla mediante varias fórmulas matemáticas predefinidas. En realidad, puede producir mucho el mismo resultado con un fotograma clave spline que puede con algunos de los tipos de función de aceleración, pero también hay algunas funciones de aceleración, como BackEase, que no se pueden reproducir con una spline.

Para aplicar una función de aceleración a un fotograma clave de aceleración, 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 rebotación.

<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 aceleración. Trataremos más en la sección siguiente.

Funciones de aceleración

Las funciones de aceleración le 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 quiera que un objeto rebote de forma realista o se comporte como si estuviera sobre un muelle. Podrías usar fotograma clave o incluso animaciones from/To/By para aproximar estos efectos, pero tomaría una cantidad significativa de trabajo y la animación sería menos precisa que usar 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 aceleración:

  • 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 tienen un poco de superposición, en función de cómo establezca las propiedades en las funciones de aceleración que tienen 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 cambiar el valor fuera del intervalo normal según lo establecido por From/To o valores de fotogramas clave. Inicia la animación cambiando el valor en la dirección opuesta como se esperaría desde un comportamiento normal de From/To , vuelve al valor From o starting de nuevo y, a continuación, ejecuta la animación como normal.

En un ejemplo anterior, se mostró cómo declarar una función de aceleración para una animación de fotograma clave. En este ejemplo siguiente se aplica una función de aceleración 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 aceleración a una animación From/To/By, cambia las características de función a lo largo del tiempo de cómo el valor interpola entre los valores From y To a lo largo de la duración de la animación. Sin una función de aceleración, sería una interpolación lineal.

Animaciones de valor de objeto discretos

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 keyTime del fotograma, el valor animado se establece inmediatamente en el valor especificado en el valor del 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 establecer 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 conjunto de fotogramas 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.