在WPF(Windows Presentation Foundation)中,动画是UI设计中一个非常强大的功能,它能够提升用户界面的交互性和视觉吸引力。在之前的一篇文章中,讨论了简单的Double动画和Color动画,它们通过定义起始和结束点来实现动画效果。然而,对于更复杂的动画效果,需要更高级的动画技术,如KeyFrame动画、路径动画和矩阵动画。这些技术提供了对动画过程更精细的控制。
KeyFrame动画基于关键帧,关键帧定义了动画的重要点,而中间帧则由WPF自动生成。路径动画允许定义对象跟随的路径,使用PathGeometry来实现,这比关键帧动画更简单。矩阵动画是一种特殊的路径动画,可以用来控制对象的位置和方向。
以下代码展示了如何使用线性关键帧动画来控制一个椭圆形状在水平方向上从0到400的移动,持续时间为5秒。同时,使用DoubleAnimationUsingKeyFrames元素来控制椭圆形状在垂直方向上的移动,它在0.5秒的间隔内指定了5个关键帧。
<Canvas>
<Ellipse Fill="Red" Width="70" Height="70">
<Ellipse.Triggers>
<EventTrigger RoutedEvent="Ellipse.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="0" To="400" Duration="0:0:5" Storyboard.TargetProperty="(Canvas.Left)" RepeatBehavior="Forever" AutoReverse="True" />
<DoubleAnimationUsingKeyFrames Duration="0:0:2" Storyboard.TargetProperty="(Canvas.Top)" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames.KeyFrames>
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0" />
<LinearDoubleKeyFrame Value="50" KeyTime="0:0:0.5" />
<LinearDoubleKeyFrame Value="200" KeyTime="0:0:1" />
<LinearDoubleKeyFrame Value="50" KeyTime="0:0:1.5" />
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:2" />
</DoubleAnimationUsingKeyFrames.KeyFrames>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Ellipse.Triggers>
</Ellipse>
</Canvas>
线性关键帧动画不会产生平滑的动画效果,因为两个帧之间的值变化是恒定的。
为了创建平滑的动画效果,可以使用SplineDoubleKeyFrame。SplineDoubleKeyFrame使用数学函数来计算对象应该如何加速或减速。KeySpline属性可以用来指定这个值。
<Canvas>
<Ellipse Fill="Red" Width="70" Height="70">
<Ellipse.Triggers>
<EventTrigger RoutedEvent="Ellipse.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="0" To="400" Duration="0:0:10" Storyboard.TargetProperty="(Canvas.Left)" RepeatBehavior="Forever" AutoReverse="True" />
<DoubleAnimationUsingKeyFrames Duration="0:0:2" Storyboard.TargetProperty="(Canvas.Top)" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames.KeyFrames>
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0" />
<SplineDoubleKeyFrame Value="50" KeyTime="0:0:0.5" KeySpline="0.4,0 0.7,0.7" />
<SplineDoubleKeyFrame Value="200" KeyTime="0:0:1" KeySpline="0.2,0.2 0.7,0.4" />
<SplineDoubleKeyFrame Value="50" KeyTime="0:0:1.5" KeySpline="0,0.3 0.75,0.75" />
<SplineDoubleKeyFrame Value="0" KeyTime="0:0:2.0" KeySpline="0.25,0.25 0.6,1" />
</DoubleAnimationUsingKeyFrames.KeyFrames>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Ellipse.Triggers>
</Ellipse>
</Canvas>
上述代码通过在开始时缓慢加速,然后逐渐加速,产生了更真实的动画效果。
路径动画可以用来在画布上移动对象,通过改变其位置。这可以通过设置Canvas.Left和Canvas.Top属性来实现。由于这些属性是double类型,可以使用DoubleAnimationUsingPath来动画化对象。
<Canvas>
<Canvas.Resources>
<PathGeometry x:Key="MyGeometry" Figures="M 0,30 A 30,30 180 0 1 60,30 30,30 180 0 1 0,30" />
</Canvas.Resources>
<Ellipse Width="50" Height="50" Fill="Green">
<Ellipse.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<DoubleAnimationUsingPath Source="X" Storyboard.TargetProperty="(Canvas.Left)" PathGeometry="{StaticResource MyGeometry}" />
<DoubleAnimationUsingPath Source="Y" Storyboard.TargetProperty="(Canvas.Top)" PathGeometry="{StaticResource MyGeometry}" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Ellipse.Triggers>
</Ellipse>
</Canvas>
上述代码创建了一个PathGeometry对象作为画布资源。然后使用DoubleAnimationUsingPath的PathGeometry属性来改变椭圆形状在路径上的位置。
矩阵动画可以用来控制对象的位置和方向。可以使用DoesRotateWithTangent属性来控制对象在路径上的旋转。
<Canvas>
<Path Name="MyPath" StrokeThickness="7">
<Path.Stroke>
<SolidColorBrush x:Name="MyBrush" Color="Red" />
</Path.Stroke>
<Path.Data>
<PathGeometry Figures="M 0,0 H45 M 35,-10 L 45,0,35,10" />
</Path.Data>
<Path.RenderTransform>
<MatrixTransform x:Name="MyMatrixTransform">
<MatrixTransform.Matrix>
<Matrix/>
</MatrixTransform.Matrix>
</MatrixTransform>
</Path.RenderTransform>
<Path.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="MyBrush" Storyboard.TargetProperty="Color" From="Red" To="Green" BeginTime="0:0:0" Duration="0:0:1" />
<ColorAnimation Storyboard.TargetName="MyBrush" Storyboard.TargetProperty="Color" From="Green" To="Blue" BeginTime="0:0:1" Duration="0:0:1" />
<ColorAnimation Storyboard.TargetName="MyBrush" Storyboard.TargetProperty="Color" From="Blue" To="Cyan" BeginTime="0:0:2" Duration="0:0:1" />
<ColorAnimation Storyboard.TargetName="MyBrush" Storyboard.TargetProperty="Color" From="Cyan" To="Magenta" BeginTime="0:0:3" Duration="0:0:1" />
<ColorAnimation Storyboard.TargetName="MyBrush" Storyboard.TargetProperty="Color" From="Magenta" To="Red" BeginTime="0:0:4" Duration="0:0:1" />
<MatrixAnimationUsingPath Storyboard.TargetName="MyMatrixTransform" Storyboard.TargetProperty="Matrix" DoesRotateWithTangent="True" Duration="0:0:5" RepeatBehavior="Forever">
<MatrixAnimationUsingPath.PathGeometry>
<PathGeometry Figures="M 100,200 C 100,25 400,350 400,175" />
</MatrixAnimationUsingPath.PathGeometry>
</MatrixAnimationUsingPath>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
</Path>
</Canvas>