关键帧动画概述

本主题介绍关键帧动画。 通过关键帧动画,可以使用两个以上的目标值进行动画处理,并控制动画的内插方法。

先决条件

若要理解本概述,用户应熟悉 Windows Presentation Foundation (WPF) 动画和时间线。 有关动画的简介,请参阅动画概述。 它还有助于熟悉 From/To/By 动画。 有关详细信息,请参阅“From/To/By 动画概述”。

什么是关键帧动画?

与 From/To/By 动画类似,关键帧动画对目标属性的值进行动画处理。 它通过其 Duration 在目标值之间创建过渡。 但是,From/To/By 动画可以在两个值之间创建过渡,而单个关键帧动画可以在任意数量的目标值之间创建过渡。 不同于 From/To/By 动画,关键帧动画没有设置其目标值所需的 From、To 或 By 属性。 关键帧动画的目标值使用关键帧对象进行描述,因此称作“关键帧动画”。 若要指定动画的目标值,请创建关键帧对象并将其添加到动画的 KeyFrames 集合。 动画运行时,将在指定的帧之间过渡。

某些关键帧方法除支持多个目标值外,甚至还支持多个内插方法。 动画的内插方法定义了从一个值过渡到下一个值的方式。 有三种内插类型:离散、线性和曲线。

若要使用关键帧动画进行动画处理,需要完成下列步骤。

  • 像针对 From/To/By 动画一样声明动画并指定其 Duration

  • 对于每一个目标值,创建一个相应类型的关键帧,设置其值和 KeyTime,并将其添加到动画的 KeyFrames 集合。

  • 以针对 From/To/By 动画的方式将该动画与属性相关联。 有关使用演示图板将动画应用到属性的详细信息,请参阅演示图板概述

以下示例使用 DoubleAnimationUsingKeyFramesRectangle 元素进行四个不同位置的动画处理。

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Microsoft.Samples.KeyFrameAnimations.KeyFramesIntroduction"
  WindowTitle="KeyFrame Animations">

  <Border Width="400" BorderBrush="Black">  
    
    <Rectangle Fill="Blue" 
      Width="50" Height="50"
      HorizontalAlignment="Left">
      <Rectangle.RenderTransform>
        <TranslateTransform 
          x:Name="MyAnimatedTranslateTransform" 
          X="0" Y="0" />
      </Rectangle.RenderTransform>
      <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Rectangle.MouseLeftButtonDown">
          <BeginStoryboard>
            <Storyboard>
            
              <!-- 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">
                <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0" />
                <LinearDoubleKeyFrame Value="350" KeyTime="0:0:2" />
                <LinearDoubleKeyFrame Value="50" KeyTime="0:0:7" />
                <LinearDoubleKeyFrame Value="200" KeyTime="0:0:8" />                          
              </DoubleAnimationUsingKeyFrames>
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </Rectangle.Triggers> 
    </Rectangle>
  </Border> 
</Page>

与 From/To/By 动画类似,可以通过在标记和代码中使用 Storyboard 或在代码中使用 BeginAnimation 方法将关键帧动画应用于属性。 还可以使用关键帧动画创建 AnimationClock,并将其应用到一个或多个属性中。 有关应用动画的不同方法的详细信息,请参阅属性动画技术概述

关键帧动画类型

由于动画会生成属性值,因此不同的属性类型具有不同的动画类型。 要为采用 Double 的属性(例如元素的 Width 属性)进行动画处理,可以使用生成 Double 值的动画。 要为采用 Point 的属性进行动画处理,请使用生成 Point 值的动画,依此类推。

关键帧动画类属于 System.Windows.Media.Animation 命名空间,并遵循以下命名约定:

<类型>AnimationUsingKeyFrames

其中 <Type> 为该类进行动画处理的值的类型

WPF 提供了以下关键帧动画类。

属性类型 对应的 From/To/By 动画类 支持的内插方法
Boolean BooleanAnimationUsingKeyFrames 离散
Byte ByteAnimationUsingKeyFrames 离散、线性、曲线
Color ColorAnimationUsingKeyFrames 离散、线性、曲线
Decimal DecimalAnimationUsingKeyFrames 离散、线性、曲线
Double DoubleAnimationUsingKeyFrames 离散、线性、曲线
Int16 Int16AnimationUsingKeyFrames 离散、线性、曲线
Int32 Int32AnimationUsingKeyFrames 离散、线性、曲线
Int64 Int64AnimationUsingKeyFrames 离散、线性、曲线
Matrix MatrixAnimationUsingKeyFrames 离散
Object ObjectAnimationUsingKeyFrames 离散
Point PointAnimationUsingKeyFrames 离散、线性、曲线
Quaternion QuaternionAnimationUsingKeyFrames 离散、线性、曲线
Rect RectAnimationUsingKeyFrames 离散、线性、曲线
Rotation3D Rotation3DAnimationUsingKeyFrames 离散、线性、曲线
Single SingleAnimationUsingKeyFrames 离散、线性、曲线
String StringAnimationUsingKeyFrames 离散
Size SizeAnimationUsingKeyFrames 离散、线性、曲线
Thickness ThicknessAnimationUsingKeyFrames 离散、线性、曲线
Vector3D Vector3DAnimationUsingKeyFrames 离散、线性、曲线
Vector VectorAnimationUsingKeyFrames 离散、线性、曲线

目标值(关键帧)和关键时间

就像在对不同属性类型进行动画处理时有不同类型的关键帧动画一样,关键帧对象的类型也各不相同:对于每种进行动画处理的值和所支持的内插方法,都有一个对象类型。 关键帧类型遵循以下命名约定:

<InterpolationMethod><Type>KeyFrame

其中 <InterpolationMethod> 是关键帧使用的内插方法,<Type> 是类进行动画处理的值的类型。 支持所有三种内插方法的关键帧动画有三种关键帧类型可供使用。 例如,可以针对 DoubleAnimationUsingKeyFrames 使用三种关键帧类型:DiscreteDoubleKeyFrameLinearDoubleKeyFrameSplineDoubleKeyFrame。 (后面部分将对内插方法进行详细说明。)

关键帧的主要目的是指定 KeyTimeValue。 每个关键帧类型都可提供这两种属性。

  • Value 属性指定关键帧的目标值。

  • KeyTime 属性指定何时(在动画的 Duration 内)到达关键帧的 Value

关键帧动画开始后,会按关键帧的 KeyTime 属性定义的顺序来循环访问其关键帧。

  • 如果 0 时刻没有关键帧,动画将在目标属性的当前值和第一个关键帧的 Value 之间创建一个过渡;否则,动画的输出值将成为第一个关键帧的值。

  • 动画将使用由第二个关键帧指定的内插方法来创建第一个和第二个关键帧的 Value 之间的过渡。 过渡起始自第一个关键帧的 KeyTime,在到达第二个关键帧的 KeyTime 时结束。

  • 动画将继续,这会创建每个后续关键帧和其前面的关键帧之间的过渡。

  • 最后,该动画过渡到具有最大关键时间(等于或小于动画的 Duration)的关键帧的值。

如果动画的 DurationAutomatic 或其 Duration 等于最后一个关键帧的时间,则动画结束。 否则,如果动画的 Duration 大于最后一个关键帧的关键时间,则动画的关键帧值将一直保留,直到到达其 Duration 的末尾为止。 与所有动画类似,关键帧动画使用其 FillBehavior 属性确定在到达其活动期末尾时是否保留最终值。 有关详细信息,请参阅计时行为概述

以下示例使用前面示例中定义的 DoubleAnimationUsingKeyFrames 对象来演示 ValueKeyTime 属性的工作方式。

  • 第一个关键帧立即将动画的输出值设置为 0。

  • 第二个关键帧在 0 和 350 之间进行动画处理。 它在第一个关键帧结束后开始(开始时间 = 0 秒),播放 2 秒钟,结束时间 = 0:0:2。

  • 第三个关键帧在 350 和 50 之间进行动画处理。 它在第二个关键帧结束时开始(开始时间 = 2 秒),播放 5 秒钟,结束时间 = 0:0:7。

  • 第四个关键帧在 50 和 200 之间进行动画处理。 它在第三个关键帧结束时开始(开始时间 = 7 秒),播放 1 秒钟,结束时间 = 0:0:8。

  • 由于动画的 Duration 属性已设置为 10 秒,所以该动画保留其最终值两秒钟,在时间 = 0:0:10 时结束。

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Microsoft.Samples.KeyFrameAnimations.KeyFramesIntroduction"
  WindowTitle="KeyFrame Animations">

  <Border Width="400" BorderBrush="Black">  
    
    <Rectangle Fill="Blue" 
      Width="50" Height="50"
      HorizontalAlignment="Left">
      <Rectangle.RenderTransform>
        <TranslateTransform 
          x:Name="MyAnimatedTranslateTransform" 
          X="0" Y="0" />
      </Rectangle.RenderTransform>
      <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Rectangle.MouseLeftButtonDown">
          <BeginStoryboard>
            <Storyboard>
            
              <!-- 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">
                <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0" />
                <LinearDoubleKeyFrame Value="350" KeyTime="0:0:2" />
                <LinearDoubleKeyFrame Value="50" KeyTime="0:0:7" />
                <LinearDoubleKeyFrame Value="200" KeyTime="0:0:8" />                          
              </DoubleAnimationUsingKeyFrames>
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </Rectangle.Triggers> 
    </Rectangle>
  </Border> 
</Page>

内插方法

前面部分提到了某些关键帧动画支持多种内插方法。 动画的内插对动画在其持续时间内在值之间进行过渡的方式进行了描述。 通过选择动画要使用哪种关键帧类型,可以定义该关键帧段的内插方法。 有三种不同类型的内插方法:线性、离散和曲线。

线性内插

使用线性内插,动画将以段持续时间的固定速度进行播放。 例如,如果关键帧段从 0 过渡到 10,持续时间为 5 秒,则动画会在指定时间输出以下值:

时间 输出值
0 0
1 2
2 4
3 6
4 8
4.25 8.5
4.5 9
5 10

离散内插

使用离散内插,动画函数将从一个值跳到下一个值,没有内插。 如果关键帧段从 0 过渡到 10,持续时间为 5 秒,则动画会在指定时间输出以下值:

时间 输出值
0 0
1 0
2 0
3 0
4 0
4.25 0
4.5 0
5 10

注意动画在段持续时间恰好结束之前不会更改其输出值的方式。

曲线内插更为复杂。 相关内容将在下一节介绍。

曲线内插

曲线内插可用于达到更现实的计时效果。 由于动画通常用于模拟现实世界中出现的效果,因此开发人员可能需要精确地控制对象的加速和减速,并需要严格地对计时段进行操作。 通过自由绘制曲线关键帧,可以使用曲线内插进行动画处理。 使用其他关键帧,可以指定 ValueKeyTime。 使用自由绘制曲线关键帧,还可以指定 KeySpline。 以下示例显示了 DoubleAnimationUsingKeyFrames 的单个自由绘制曲线关键帧。 请注意 KeySpline 属性,它就是自由绘制曲线关键帧与其他类型的关键帧的不同之处。

<SplineDoubleKeyFrame Value="500" KeyTime="0:0:7" KeySpline="0.0,1.0 1.0,0.0" />

一条三次方贝塞尔曲线由一个起点、一个终点和两个控制点定义。 自由绘制曲线关键帧的 KeySpline 属性定义从 (0,0) 延伸到 (1,1) 的贝塞尔曲线的两个控制点。 第一个控制点控制贝塞尔曲线前半部分的曲线因子,第二个控制点控制贝塞尔线段后半部分的曲线因子。 生成的曲线描述了该自由绘制曲线关键帧的变化率。 曲线陡度越大,关键帧更改其值的速度越快。 曲线趋于平缓时,关键帧更改其值的速度也趋于缓慢。

可以使用 KeySpline 模拟下落的水滴或跳动的球等的物理轨迹,或者将其他“渐入”和“渐出”效果应用于运动动画。 对于用户交互效果(例如背景淡入/淡出或控制按钮弹跳等),可能要应用曲线内插,以便以特定方式提高或降低动画的变化率。

以下示例将 KeySpline 指定为 0,1 1,0,从而创建了以下贝塞尔曲线。

A Bezier curve
控制点为 (0.0, 1.0) 和 (1.0, 0.0) 的主曲线

<SplineDoubleKeyFrame Value="500" KeyTime="0:0:7" KeySpline="0.0,1.0 1.0,0.0" />

此关键帧的动画处理在开始时快速进行,减速,然后再次加速,直到结束。

以下示例将 KeySpline 指定为 0.5,0.25 0.75,1.0,从而创建如下贝塞尔曲线。

A second Bezier curve example.
控制点为 (0.25, 0.5) 和 (0.75, 1.0) 的主曲线

<SplineDoubleKeyFrame Value="350" KeyTime="0:0:15"  KeySpline="0.25,0.5 0.75,1" />

由于贝塞尔曲线的曲度变化幅度很小,因此该关键帧的动画处理速率几乎固定不变;只在接近结束时才开始减速。

以下示例使用 DoubleAnimationUsingKeyFrames 为矩形的位置添加动画效果。 因为 DoubleAnimationUsingKeyFrames 使用 SplineDoubleKeyFrame 对象,每个关键帧值之间的转换都使用曲线内插。

<!-- This rectangle is animated using a key frame animation
     with splined interpolation. -->
<Rectangle 
  Width="50"
  Height="50"
  Fill="Purple">  
  <Rectangle.RenderTransform>
    <TranslateTransform 
      x:Name="SplineAnimatedTranslateTransform" 
      X="0" Y="0" />
  </Rectangle.RenderTransform>
  <Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.Loaded">
      <BeginStoryboard>
        <Storyboard>

          <!-- Animate the TranslateTransform's X property
               from its base value (0) to 500, then 200,
               then 350 over 15 seconds. -->
          <DoubleAnimationUsingKeyFrames
            Storyboard.TargetName="SplineAnimatedTranslateTransform"
            Storyboard.TargetProperty="X"
            Duration="0:0:15"
            RepeatBehavior="Forever">                
            <SplineDoubleKeyFrame Value="500" KeyTime="0:0:7" KeySpline="0.0,1.0 1.0,0.0" />
            
            <SplineDoubleKeyFrame Value="200" KeyTime="0:0:10"  KeySpline="0.0,0.0 1.0,0.0" />

            <SplineDoubleKeyFrame Value="350" KeyTime="0:0:15"  KeySpline="0.25,0.5 0.75,1" />
          </DoubleAnimationUsingKeyFrames>           
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers> 
</Rectangle>

曲线内插可能很难理解;使用不同的设置进行体验有助于理解。 通过主曲线动画示例,可以更改主曲线值,并查看由此所产生的动画结果。

组合内插方法

可在一个关键帧动画中使用具有不同内插类型的关键帧。 如果两个具有不同内插的关键帧动画彼此跟随,第二个关键帧的内插方法将用于创建从第一个值到第二个值的过渡。

在以下示例中,将创建一个使用线性、曲线和离散内插的 DoubleAnimationUsingKeyFrames

<!-- This rectangle is animated using a key frame animation
     with a combination of interpolation methods. -->
<Rectangle 
  Width="50"
  Height="50"
  Fill="Orange">  
  <Rectangle.RenderTransform>
    <TranslateTransform 
      x:Name="ComboAnimatedTranslateTransform" 
      X="0" Y="0" />
  </Rectangle.RenderTransform>
  <Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.Loaded">
      <BeginStoryboard>
        <Storyboard>

          <!-- Animate the TranslateTransform's X property
               from its base value (0) to 500, then 200,
               then 350 over 15 seconds. -->
          <DoubleAnimationUsingKeyFrames
            Storyboard.TargetName="ComboAnimatedTranslateTransform"
            Storyboard.TargetProperty="X"
            Duration="0:0:15"
            RepeatBehavior="Forever">
            <DiscreteDoubleKeyFrame Value="500" KeyTime="0:0:7" />
            <LinearDoubleKeyFrame Value="200" KeyTime="0:0:10" />
            <SplineDoubleKeyFrame Value="350" KeyTime="0:0:15"  
              KeySpline="0.25,0.5 0.75,1" />                      
          </DoubleAnimationUsingKeyFrames>           
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers> 
</Rectangle>

有关持续时间和关键时间的更多信息

与其他动画一样,关键帧动画具有 Duration 属性。 除了指定动画的 Duration 外,还需要指定向每个关键帧分配持续时间内的多长一段时间。 可以通过为动画的每个关键帧描述 KeyTime 来实现此目的。 每个关键帧的 KeyTime 指定该关键帧的结束时间。

KeyTime 属性并不指定关键时间的播放时长。 关键帧的播放时长由关键帧的结束时间、前一个关键帧的结束时间以及动画的持续时间确定。 关键时间可以指定为时间值、百分比或特殊值 UniformPaced

下表描述了指定关键时间的不同方式。

TimeSpan 值

可以使用 TimeSpan 值来指定 KeyTime。 该值应大于或等于 0 并且小于或等于动画的持续时间。 以下示例演示一个持续时间为 10 秒钟、有四个关键帧(这些关键帧的关键时间指定为时间值)的动画。

  • 在前 3 秒钟内,第一个关键帧在基值和 100 之间进行动画处理,结束时间 = 0:0:03。

  • 第二个关键帧在 100 和 200 之间进行动画处理。 它在第一个关键帧结束后开始(开始时间 = 3 秒),播放 5 秒钟,结束时间 = 0:0:8。

  • 第三个关键帧在 200 和 500 之间进行动画处理。 它在第二个关键帧结束时开始(开始时间 = 8 秒),播放 1 秒钟,结束时间 = 0:0:9。

  • 第四个关键帧在 500 和 600 之间进行动画处理。 它在第三个关键帧结束时开始(开始时间 = 9 秒),播放 1 秒钟,结束时间 = 0:0:10。

<!-- This rectangle is animated with KeyTimes using TimeSpan values. 
     Goes to 100 in the first 3 seconds, 100 to 200 in 
     the next 5 seconds, 300 to 500 in the next second,
     and 500 to 600 in the final second. -->
<Rectangle Width="50" Height="50" Fill="Blue">
  <Rectangle.RenderTransform>
    <TranslateTransform x:Name="TranslateTransform01" X="10" Y="30" />
  </Rectangle.RenderTransform>
  <Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.Loaded">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimationUsingKeyFrames 
            Storyboard.TargetName="TranslateTransform01" 
            Storyboard.TargetProperty="X"
            Duration="0:0:10"
            RepeatBehavior="Forever">

            <!-- KeyTime properties are expressed as TimeSpan values 
                 which are in the form of "hours:minutes:seconds". -->
            <LinearDoubleKeyFrame Value="100" KeyTime="0:0:3" />
            <LinearDoubleKeyFrame Value="200" KeyTime="0:0:8" />
            <LinearDoubleKeyFrame Value="500" KeyTime="0:0:9" />
            <LinearDoubleKeyFrame Value="600" KeyTime="0:0:10" />
          </DoubleAnimationUsingKeyFrames>
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers>
</Rectangle>

百分比值

百分比值指定关键帧在动画的 Duration 内的某百分比处结束。 在 XAML 中,指定百分比作为 % 符号后的数字。 在代码中,使用 FromPercent 方法并向其传递一个表示百分比的 Double。 该值必须大于或等于 0 并且小于或等于 100%。 以下示例演示一个持续时间为 10 秒钟、有四个关键帧(这些关键帧的关键时间指定为百分比)的动画。

  • 在前 3 秒钟内,第一个关键帧将在基值和 100 之间进行动画处理,结束时间 = 0:0:3。

  • 第二个关键帧在 100 和 200 之间进行动画处理。 它在第一个关键帧结束后开始(开始时间 = 3 秒),播放 5 秒钟,结束时间 = 0:0:8 (0.8 * 10 = 8)。

  • 第三个关键帧在 200 和 500 之间进行动画处理。 它在第二个关键帧结束时开始(开始时间 = 8 秒),播放 1 秒钟,结束时间 = 0:0:9 (0.9 * 10 = 9)。

  • 第四个关键帧在 500 和 600 之间进行动画处理。 它在第三个关键帧结束时开始(开始时间 = 9 秒),播放 1 秒钟,结束时间 = 0:0:10 (1 * 10 = 10)。

<!-- Identical animation behavior to the previous rectangle 
     but using percentage values for KeyTimes rather then TimeSpan. -->
<Rectangle Height="50" Width="50" Fill="Purple">
  <Rectangle.RenderTransform>
    <TranslateTransform x:Name="TranslateTransform02" X="10" Y="110" />
  </Rectangle.RenderTransform>
  <Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.Loaded">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimationUsingKeyFrames 
            Storyboard.TargetName="TranslateTransform02" 
            Storyboard.TargetProperty="X"
            Duration="0:0:10"
            RepeatBehavior="Forever">

            <!-- KeyTime properties are expressed as Percentages. -->
            <LinearDoubleKeyFrame Value="100" KeyTime="30%" />
            <LinearDoubleKeyFrame Value="200" KeyTime="80%" />
            <LinearDoubleKeyFrame Value="500" KeyTime="90%" />
            <LinearDoubleKeyFrame Value="600" KeyTime="100%" />
          </DoubleAnimationUsingKeyFrames>
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers>
</Rectangle>

特殊值 Uniform

如果希望每个关键帧的持续时间都相同,应使用 Uniform 计时。

Uniform 关键时间按关键帧的数量平均分配可用时间,以确定每个关键帧的结束时间。 以下示例演示一个持续时间为 10 秒钟、有四个关键帧(这些关键帧的关键时间指定为 Uniform)的动画。

  • 在前 2.5 秒钟内,第一个关键帧在基值和 100 之间进行动画处理,结束时间 = 0:0:2.5。

  • 第二个关键帧在 100 和 200 之间进行动画处理。 它在第一个关键帧结束后开始(开始时间 = 2.5 秒),播放大约 2.5 秒钟,结束时间 = 0:0:5。

  • 第三个关键帧在 200 和 500 之间进行动画处理。 它在第二个关键帧结束时开始(开始时间 = 5 秒),播放 2.5 秒钟,结束时间 = 0:0:7.5。

  • 第四个关键帧在 500 和 600 之间进行动画处理。 它在第二个关键帧结束时开始(开始时间 = 7.5 秒),播放 2.5 秒钟,结束时间 = 0:0:1。

<!-- This rectangle is animated with KeyTimes using Uniform values.  -->
<Rectangle Height="50" Width="50" Fill="Red">
  <Rectangle.RenderTransform>
    <TranslateTransform x:Name="TranslateTransform03" X="10" Y="190" />
  </Rectangle.RenderTransform>
  <Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.Loaded">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimationUsingKeyFrames 
            Storyboard.TargetName="TranslateTransform03" 
            Storyboard.TargetProperty="X"
            Duration="0:0:10"
            RepeatBehavior="Forever">

            <!-- KeyTime properties are expressed with values of Uniform. 
                 When a key time is set to "Uniform" the total allotted 
                 time of the animation is divided evenly between key frames.  
                 In this example, the total duration of the animation is 
                 ten seconds and there are four key frames each of which 
                 are set to "Uniform", therefore, the duration of each key frame 
                 is 3.3 seconds (10/3). -->
            <LinearDoubleKeyFrame Value="100" KeyTime="Uniform" />
            <LinearDoubleKeyFrame Value="200" KeyTime="Uniform" />
            <LinearDoubleKeyFrame Value="500" KeyTime="Uniform" />
            <LinearDoubleKeyFrame Value="600" KeyTime="Uniform" />
          </DoubleAnimationUsingKeyFrames>
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers>
</Rectangle>

特殊值 Paced

如果希望以固定速率进行动画处理,应使用 Paced 计时。

Paced 关键时间根据每一关键帧的长度来分配可用时间,以确定每帧的持续时间。 这样,动画的速度或速率将保持不变。 以下示例演示一个持续时间为 10 秒钟、有三个关键帧(这些关键帧的关键时间指定为 Paced)的动画。

<!-- Using Paced Values. Rectangle moves between key frames at 
     uniform rate except for first key frame
     because using a Paced value on the first KeyFrame in a 
     collection of frames gives a time of zero. -->
<Rectangle Height="50" Width="50" Fill="Orange">
  <Rectangle.RenderTransform>
    <TranslateTransform x:Name="TranslateTransform04" X="10" Y="270" />
  </Rectangle.RenderTransform>
  <Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.Loaded">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimationUsingKeyFrames 
            Storyboard.TargetName="TranslateTransform04" 
            Storyboard.TargetProperty="X"
            Duration="0:0:10"
            RepeatBehavior="Forever">

            <!-- KeyTime properties are expressed with values of Paced. 
                 Paced values are used when a constant rate is desired. 
                 The time allocated to a key frame with a KeyTime of "Paced" 
                 is determined by the time allocated to the other key 
                 frames of the animation. This time is calculated to 
                 attempt to give a "paced" or "constant velocity" 
                 for the animation. -->
            <LinearDoubleKeyFrame Value="100" KeyTime="Paced" />
            <LinearDoubleKeyFrame Value="200" KeyTime="Paced" />
            <LinearDoubleKeyFrame Value="500" KeyTime="Paced" />
            <LinearDoubleKeyFrame Value="600" KeyTime="Paced" />
          </DoubleAnimationUsingKeyFrames>
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers>
</Rectangle>

请注意,如果最后一个关键帧的关键时间为 PacedUniform,则其解析的关键时间将设置为 100%。 如果多帧动画中的第一个关键帧为固定速度,其解析的关键时间将设置为 0。 (如果关键帧集合仅包含一个关键帧,并且是一个固定速度的关键帧,其解析的关键时间将设置为 100%。)

一个关键帧动画中的不同关键帧可使用不同的关键时间类型。

组合关键时间,顺序紊乱的关键帧

可在同一动画中使用具有不同 KeyTime 值类型的关键帧。 尽管建议以关键帧的实际播放顺序来添加关键帧,但此操作不是必需的。 动画和计时系统能够处理顺序紊乱的关键帧。 将忽略关键时间无效的关键帧。

下表描述了为关键帧动画的关键帧解析关键时间的过程。

  1. 解析 TimeSpanKeyTime 值。

  2. 确定动画的总内插时间,即关键帧动画完成向前迭代所需的全部时间。

    1. 如果动画的 Duration 不是 AutomaticForever,则总内插时间是动画的 Duration 属性的值。

    2. 否则,总内插时间是其关键帧中所指定的 TimeSpanKeyTime 最大值(如果存在这样的值)。

    3. 否则,总内插时间为 1 秒。

  3. 使用总内插时间值来解析 PercentKeyTime 值。

  4. 如果最后一个关键帧尚未在之前步骤中解析,则将解析该关键帧。 如果最后一个关键帧的 KeyTimeUniformPaced,则其解析时间将等于总内插时间。

    如果第一个关键帧的 KeyTimePaced 并且此动画有多个关键帧,则将其 KeyTime 值解析为零;如果只有一个关键帧且其 KeyTime 值为 Paced,则解析为总内插时间,如上一步所述。

  5. 解析其余的 UniformKeyTime 值:它们将平均分配可用时间。 在此过程中,会暂时将未解析的 PacedKeyTime 值视为 UniformKeyTime 值,并获得一个临时解析时间。

  6. 使用距离最近的、具有已解析的 KeyTime 值的已声明关键帧,解析关键时间未指定的关键帧的 KeyTime 值。

  7. 解析剩余 PacedKeyTime 值。 PacedKeyTime 使用相邻关键帧的 KeyTime 值来确定其解析时间。 目的是确保动画速度在此关键帧的解析时间内保持固定不变。

  8. 将关键帧按解析时间(主键)以及声明顺序(次键)进行排序,换言之,根据解析关键帧 KeyTime 值按固定顺序进行排序。

另请参阅