书名:WPF专业编程指南
作者:李应保
出版社:电子工业出版社
出版时间:2010-01
ISBN:9787121100116
第15章 动画
一、KeyFrame
WPF动画最重要的一类是KeyFrame类,表15-1列出的22种数据类型,若某个数据类型的值是可以连续变化的,则WPF提供两种类型的动画。如Int16,有Int16Animation类和Int16AnimationUsingKeyFrame,本章前面所讲述的动画一概没有涉及KeyFrame。若某个数据类型不能连续变化,WPF只提供一种动画,即使用KeyFrame。Bool、Char、String和Matrix是这种类型。所谓KeyFrame动画,程序员需要为某个相关属性在特定的时间给出特定的值。 对于连续变化的相关属性,WPF根据设定的动画属性,计算出在某个时刻的相应值(在没有设置加速或减速的情况下,通常是线性插值)。使用KeyFrame可以更精确、更灵活地控制动画。
使用KeyFrame可以完成前面所述的动画的所有功能,Microsoft所开发的WPF工具Express Blend只支持KeyFrame动画,由此可知KeyFrame在动画中的突出地位。
xxxAnimationKeyFrames是一个包容器类,其中可以含有任意多个xxxKeyFrame类,这里xxx为22种数据类型中的一个。
×××KeyFrame为抽象类,对于可以连续变化的数据类型,从xxxKeyFrame中派生出三个类:DiscreteXXXKeyFrame、LinearXXXKeyFrame和SplineXXXKeyFrame,其中xxx为数据类型。例如颜色的动画,共有ColorAnimationUsingKeyFrames、ColorKeyFrame、DiscreteColorKeyFrame、LinearColorKeyFrame和SplineColorKeyFrame。图15-8示出了这5个类间关系的UML表示。

对于不可以连续变化的数据类型,xxxKeyFrame只有一个派生类,即DiscreteXXXKeyFrame。使用KeyFrame时,启动故事板(BeginStoryboard)的机制和15.5.3节的XXXAnimation相同,即UsingKeyFrames是在Storyboard这个级别。
1 线性KeyFrame
下面是一个拍球的动画例子。在这个例子中,对球(椭圆)的两个属性进行了动画,一个是其填充色,另一个是其在平面上的位置。完整的XAML如下:
<Window x:Class="StoryBoard.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:StoryBoard"
mc:Ignorable="d"
x:Name="Window" Title="使用KeyFrame1" Width="287" Height="480">
<Window.Resources>
<Storyboard x:Key="bouncing" RepeatBehavior="Forever" >
<ColorAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="ellipse"
Storyboard.TargetProperty
="(Shape.Fill).(SolidColorBrush.Color)">
<LinearColorKeyFrame KeyTime="00:00:00"
Value="#FF8C1010"/>
<LinearColorKeyFrame KeyTime="00:00:03"
Value="#FF8B8C10"/>
<LinearColorKeyFrame KeyTime="00:00:06"
Value="#FF8C3D10"/>
</ColorAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="ellipse"
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[3].(TranslateTransform.Y)">
<LinearDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
<LinearDoubleKeyFrame KeyTime="00:00:03" Value="293"/>
<LinearDoubleKeyFrame KeyTime="00:00:06" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource bouncing}"/>
</EventTrigger>
</Window.Triggers>
<Grid x:Name="LayoutRoot" Width="264">
<Ellipse Fill="#FFFFFFFF" Stroke="#FF000000"
HorizontalAlignment="Left" Margin="92,70,0,0"
VerticalAlignment="Top" Width="64" Height="56"
x:Name="ellipse" RenderTransformOrigin="0.5,0.5">
<Ellipse.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1"/>
<SkewTransform AngleX="0" AngleY="0"/>
<RotateTransform Angle="0"/>
<TranslateTransform X="0" Y="0"/>
</TransformGroup>
</Ellipse.RenderTransform>
</Ellipse>
</Grid>
</Window>
