本主题介绍 Silverlight 中的关键帧动画。 通过关键帧动画,您可以使用两个以上的目标值制作动画,并控制动画的内插方法。
本主题包括下列各节。
与 From/To/By 动画类似,关键帧动画以动画形式显示了目标属性的值。 它通过其 Duration 创建其目标值之间的过渡。 但是,From/To/By 动画创建两个值之间的过渡,而单个关键帧动画可以创建任意数量的目标值之间的过渡。
与 From/To/By 动画不同,关键帧动画没有设置其目标值所需的 From、To 或 By 属性。 而是使用关键帧对象描述关键帧动画的目标值。 若要指定动画的目标值,需要创建关键帧对象并将其添加到动画的 KeyFrames 属性。 动画运行时,将在您指定的帧之间过渡。
某些关键帧方法除支持多个目标值外,还支持多个内插方法。 动画的内插方法定义了从某个值过渡到下一个值的方式。 有三种内插类型:离散、线性和样条。
若要使用关键帧动画进行动画处理,需要完成下列步骤:
-
按照对 From/To/By 动画使用的方法声明动画并指定其 Duration。
-
按照对 From/To/By 动画使用的方法,将动画与属性相关联。
下面的示例使用 DoubleAnimationUsingKeyFrames 对象对跨屏幕的 Rectangle 元素进行动画处理。
<Canvas><Canvas.Resources><Storyboardx:Name="myStoryboard"><!-- Animate the TranslateTransform's X property from 0 to 350, then 50, then 200 over 10 seconds. --><DoubleAnimationUsingKeyFramesStoryboard.TargetName="MyAnimatedTranslateTransform"Storyboard.TargetProperty="X"Duration="0:0:10"><!-- Using a LinearDoubleKeyFrame, the rectangle moves steadily from its starting position to 500 over the first 3 seconds. --><LinearDoubleKeyFrameValue="500"KeyTime="0:0:3"/><!-- Using a DiscreteDoubleKeyFrame, the rectangle suddenly appears at 400 after the fourth second of the animation. --><DiscreteDoubleKeyFrameValue="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. --><SplineDoubleKeyFrameKeySpline="0.6,0.0 0.9,0.00"Value="0"KeyTime="0:0:6"/></DoubleAnimationUsingKeyFrames></Storyboard></Canvas.Resources><RectangleMouseLeftButtonDown="Mouse_Clicked"Fill="Blue"Width="50"Height="50"><Rectangle.RenderTransform><TranslateTransformx:Name="MyAnimatedTranslateTransform"X="0"Y="0"/></Rectangle.RenderTransform></Rectangle></Canvas>
// When the user clicks the Rectangle, the animation// begins.privatevoid Mouse_Clicked(object sender, MouseEventArgs e) { myStoryboard.Begin(); }
就像在 From/To/By 动画中一样,使用 Storyboard 对象将关键帧动画应用于属性。
关键帧的主要用途是指定 KeyTime 和目标 Value。 每一个关键帧类型(用于键入值的抽象类型和用于定义内插技术的派生类型)都提供了这两个属性。
-
Value 属性指定关键帧的目标值。
-
KeyTime 属性指定到达关键帧的 Value 的时间(在动画的 Duration 之内)。
关键帧动画开始后,它会按照由其 KeyTime 属性定义的顺序来循环访问其关键帧。
-
如果时间 0 上没有关键帧,动画将在目标属性当前值和第一个关键帧的 Value 之间创建一个过渡;否则,动画的输出值将成为第一个关键帧的值。
-
动画会使用由第二个关键帧指定的内插方法来创建第一个和第二个关键帧的 Value 之间的过渡。 过渡起始自第一个关键帧的 KeyTime,在到达第二个关键帧的 KeyTime 时结束。
-
动画将继续,并创建每个后续关键帧及其前面的关键帧之间的过渡。
-
最终,动画过渡到关键时间最大(等于或小于动画的 Duration)的关键帧值。
如果动画的 Duration 为"Automatic"或其 Duration 等于最后一个关键帧的时间,动画将结束。 如果动画的 Duration 大于最后一个关键帧的关键时间,动画将保持关键帧值,直到到达其 Duration 的末尾为止。 如果动画的 Duration 小于最后一个关键帧,动画将在到达持续时间后立即进入填充期。
与所有动画类似,关键帧动画使用其 FillBehavior 属性来确定在到达其活动期末尾时是否保留最终值。
关键帧的类型
就像对不同特性类型进行动画处理时有不同类型的关键帧动画一样,关键帧对象的类型也各不相同:对于每种进行动画处理的值和所支持的内插方法,都有一个对象类型。 关键帧类型遵循以下命名约定:
_interpolationMethod_typeKeyFrame
其中,_interpolationMethod 是关键帧使用的内插方法,_type 是类要进行动画处理的值的类型。
支持所有三种内插方法的关键帧动画有三种关键帧类型可供您使用。 例如,您可以使用以下三种具有 DoubleAnimationUsingKeyFrames 的关键帧类型:DiscreteDoubleKeyFrame、LinearDoubleKeyFrame 和 SplineDoubleKeyFrame。 (内插方法对内插方法进行了详细说明。)
目标值和关键时间示例
下面的示例使用在前面的示例中定义的 DoubleAnimationUsingKeyFrames 对象来演示 Value 和 KeyTime 属性的工作方式。
-
第一个关键帧立即将动画的输出值设置为 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 处结束之前,动画将保留其最终值两秒钟。 由于 FillBehavior 属性设置为 Stop,因此当时间结束时,矩形将返回到其原始位置。
<Canvas> <Canvas.Resources> <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" FillBehavior="Stop"> <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> </Canvas.Resources> <Rectangle MouseLeftButtonDown="Mouse_Clicked" Fill="Blue" Width="50" Height="50"> <Rectangle.RenderTransform> <TranslateTransform x:Name="MyAnimatedTranslateTransform" X="0" Y="0" /> </Rectangle.RenderTransform> </Rectangle> </Canvas>
// When the user clicks the Rectangle, the animation begins. public void Mouse_Clicked(object sender, MouseEventArgs e) { myStoryboard.Begin(); }
如前面所述,某些关键帧动画支持多种内插方法。 动画的内插描述了动画在其持续时间内如何在各个值之间进行过渡。 通过选择动画将要使用哪种关键帧类型,可以定义该关键帧段的内插方法。 有三种不同类型的内插方法:线性、离散和样条。
线性内插
使用线性内插,动画将以段持续期间内的固定速度来播放。 例如,如果关键帧段在 5 秒内从 0 过渡到 10,则该动画会在指定的时间产生如下表所示的值。
时间 | 输出值 |
---|---|
0 | 0 |
1 | 2 |
2 | 4 |
3 | 6 |
4 | 8 |
4.25 | 8.5 |
4.5 | 9 |
5 | 10 |
离散内插
使用离散内插,动画函数将从一个值跳到下一个没有内插的值。 如果关键帧段在 5 秒内从 0 过渡到 10,则该动画会在指定的时间产生如下表所示的值。
时间 | 输出值 |
---|---|
0 | 0 |
1 | 0 |
2 | 0 |
3 | 0 |
4 | 0 |
4.25 | 0 |
4.5 | 0 |
5 | 10 |
请注意,动画在段持续期间恰好结束之前不会更改其输出值。
样条内插更为复杂。 有关内容将在下一部分介绍。
样条内插
样条内插可用于达到更现实的计时效果。 由于动画通常用于模拟现实世界中发生的效果,因此您可能需要精确地控制对象的加速和减速,并且需要严格地对计时段进行操作。 通过样条关键帧,您可以使用样条内插进行动画处理。 使用其他关键帧,您可以指定一个 Value 和 KeyTime。 使用样条关键帧,您还可以指定一个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 对表示内插的贝塞尔曲线的影响。
您可以使用 KeySpline 来模拟下落的水滴或跳动的球等物体的物理轨迹,或者将"渐入"和"渐出"效果应用于动画。 对于用户交互效果,例如背景淡入/淡出或控制按钮弹跳等,您可能要应用样条内插,以便按照特定的方式来提高或降低动画的更改速率。
下面的示例指定一条控制点为 0,1 和 1,0 的 KeySpline。
<SplineDoubleKeyFrame Value="500" KeyTime="0:0:7" KeySpline="0.0,1.0 1.0,0.0" />
下图演示了该贝塞尔曲线样条。
![显示样条的控制点。 显示样条的控制点。](http://i.msdn.microsoft.com/dynimg/IC248083.png)
上面的关键帧在开始时快速运动,再减速,然后再次加速,直到结束。
下面的示例指定一条控制点为 0.5,0.25 和 0.75,1.0 的 KeySpline。
<SplineDoubleKeyFrame Value="350" KeyTime="0:0:15" KeySpline="0.25,0.5 0.75,1" />
下图演示了该贝塞尔曲线。
![显示样条的控制点。 显示样条的控制点。](http://i.msdn.microsoft.com/dynimg/IC248101.png)
由于贝塞尔曲线的曲度变化幅度很小,此关键帧的运动速率几乎固定不变;只在将近接近结束时才开始减速。
下面的示例使用 DoubleAnimationUsingKeyFrames 对矩形的位置进行动画处理。 由于 DoubleAnimationUsingKeyFrames 使用 SplineDoubleKeyFrame 对象,因此每个关键帧值之间的过渡都使用样条内插。
<Canvas><Canvas.Resources><Storyboardx:Name="myStoryboard"><!-- Animate the TranslateTransform's X property from its base value (0) to 500, then 200, then 350 over 15 seconds. --><DoubleAnimationUsingKeyFramesStoryboard.TargetName="SplineAnimatedTranslateTransform"Storyboard.TargetProperty="X"Duration="0:0:15"><SplineDoubleKeyFrameValue="500"KeyTime="0:0:7"KeySpline="0.0,1.0 1.0,0.0"/><SplineDoubleKeyFrameValue="200"KeyTime="0:0:10"KeySpline="0.0,0.0 1.0,0.0"/><SplineDoubleKeyFrameValue="350"KeyTime="0:0:15"KeySpline="0.25,0.5 0.75,1"/></DoubleAnimationUsingKeyFrames></Storyboard></Canvas.Resources><RectangleMouseLeftButtonDown="Mouse_Clicked"Fill="Blue"Width="50"Height="50"><Rectangle.RenderTransform><TranslateTransformx:Name="SplineAnimatedTranslateTransform"X="0"Y="0"/></Rectangle.RenderTransform></Rectangle></Canvas>
// When the user clicks the Rectangle, the animation// begins.privatevoid Mouse_Clicked(object sender, MouseEventArgs e) { myStoryboard.Begin(); }
样条内插可能很难理解;请使用不同的设置进行体验,这会有助于理解。
组合内插方法
可以在单个关键帧动画中使用具有不同内插类型的关键帧。 如果两个具有不同内插的关键帧动画彼此跟随,第二个关键帧的内插方法将用于创建从第一个值到第二个值的过渡。 有关在一个关键帧动画中使用线性、样条和离散内插的示例,请参见什么是关键帧动画?。
有关持续时间和关键时间的更多信息
像其他动画一样,关键帧动画具有 Duration 属性。 除了指定动画的 Duration 外,还必须指定为每个关键帧保留该持续时间的哪个部分。 可以通过描述动画的每个关键帧的 KeyTime 来实现此目的。 每个关键帧的 KeyTime 都指定了该关键帧的结束时间。
KeyTime 属性并不指定关键帧的播放的长度。 关键帧播放时间长度由关键帧的结束时间、前一个关键帧的结束时间以及动画的持续时间来确定。
可以使用时间值来指定 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。
<Canvas><Canvas.Resources><Storyboardx:Name="myStoryboard"><DoubleAnimationUsingKeyFramesStoryboard.TargetName="MyAnimatedTranslateTransform"Storyboard.TargetProperty="X"Duration="0:0:10"><!-- KeyTime properties are expressed as TimeSpan values. --><LinearDoubleKeyFrameValue="100"KeyTime="0:0:3"/><LinearDoubleKeyFrameValue="200"KeyTime="0:0:8"/><LinearDoubleKeyFrameValue="500"KeyTime="0:0:9"/><LinearDoubleKeyFrameValue="600"KeyTime="0:0:10"/></DoubleAnimationUsingKeyFrames></Storyboard></Canvas.Resources><RectangleMouseLeftButtonDown="Mouse_Clicked"Fill="Blue"Width="50"Height="50"><Rectangle.RenderTransform><TranslateTransformx:Name="MyAnimatedTranslateTransform"X="0"Y="0"/></Rectangle.RenderTransform></Rectangle></Canvas>
// When the user clicks the Rectangle, the animation// begins.privatevoid Mouse_Clicked(object sender, MouseEventArgs e) { myStoryboard.Begin(); }