概述
目录
一、概述
二、简单独立动画
2.1 简单线性动画
2.2 高级动画控制
2.3 关键帧动画
2.4 特殊的关键帧
2.5 路径动画
三、场景
一、概述
动画的本质就是在一个时间段内对象位置、角度、颜色、透明度等属性值的连续变化。这些属性种,有些是对象自身的单属性,有些是图形变形 的属性。WPF规定,可以用来制作动画的属性必须是依赖属性。
简单的动画由一个元素来完成就可以了,就像一个演员的独角戏,WPF吧简单动画称为AnimationTimeline。复杂的动画就需要UI上的多个元素协同完成,就像电影中的一段场景。复杂动画的协同包括有哪些UI元素参与动画、每个元素的动画行为是什么、动画何时开始何时结束等。WPF把一组协同的动画也称为Storyboard。
二、简单独立动画
动画就是“会动的画”,而这个会动值得就是能够让UI元素或元素变形的某个属性值产生连续变化。任何一个属性都有自己的数据类型,比如UIElement的With和Height属性为Double类型、Window的Title属性为String类型。几乎针对每个可能的数据类型,WPF的动画子系统都为其准备了相应的动画类,这些动画类均派生自AnimationTimeline。3种具体动画,即简单动画、关键帧动画、沿路径运动的动画。例如:DoubleAnimationbase,它完整地派生了3个具体动画:DoubleAnimation、DoubleAnimationUsingKeyFrames和DoubleAnimationUsingPath,分别是简单动画、关键帧动画、沿路径运动的动画。
在WPF中,Double类型的属性用的最多,只讲这个类,其他亦可触类旁通。
2.1 简单线性动画
简单线性动画指仅有变化起点、变化终点、变化幅度、变化时间4个要素构成的动画。
变化时间(Duration 属性):必须指定,动画的时长多少
变化终点(To 属性):变化终点,如果没有则采用 上一次动画的终点 或 默认值
变化幅度(By 属性):变化幅度,变化的规律,使用时不可使用变化终点
变化起点(From 属性):变化起点,如果没有指定则以目标属性的当前值为起点。
让我们分析一个简单的实例。例子的XAML代码如下:
<Grid>
<Button Width="60" Height="60" Content="Move" Click="Button_Click_1"
HorizontalAlignment="Left" VerticalAlignment="Top">
<Button.RenderTransform>
<TranslateTransform x:Name="tt" X="30" Y="30"/>
</Button.RenderTransform>
</Button>
</Grid>
</Window>
用户界面上只包含一个Button,这个Button的RenderTransform属性值是一个名为tt的TranslateTransform对象,改变这个对象的X和Y值就会让Button的显示位置变化。Button的Click事件处理器代码如下:
private void Button_Click(object sender, RoutedEventArgs e)
{
DoubleAnimation daX = new DoubleAnimation();
DoubleAnimation daY = new DoubleAnimation();
//指定起点
daX.From = 30;
daY.From = 30;
//指定终点
Random r = new Random();
daX.To = r.NextDouble() * 300;
daY.To = r.NextDouble() * 300;
//指定时长
Duration duration = new Duration(TimeSpan.FromMilliseconds(300));
daX.Duration = duration;
daY.Duration = duration;
//动画的主题是TranslateTransform变形,而非Button
this.tt.BeginAnimation(TranslateTransform.XProperty, daX);
this.tt.BeginAnimation(TranslateTransform.YProperty, daY);
}
因为TranslateTransform的X、Y属性均为Double类型,所以选用DoubleAnimation来产生变化。代码中声明了daX和daY两个DoubleAnimation变量并分别创建引用实例。接下来的代码一次为它们设置了起始值、终止值、变化时间。最后调用DoubleAnimation方法,让daX作用在TranslateTransform的XProperty依赖属性上、让daY作用在TranslateTransform的YProperty依赖属性上。
每次单击按钮,按钮都会从起始位置向右下长宽不超过300像素的矩形内的某点运动,完成运动的时长是300毫秒。
效果:
如果把事件处理器的代码改变成这样:
private void Button_Click(object sender, RoutedEventArgs e)
{
DoubleAnimation daX = new DoubleAnimation();
DoubleAnimation daY = new DoubleAnimation();
//指定幅度
daX.By= 100D;
daY.By = 100D;
//指定时长
Duration duration = new Duration(TimeSpan.FromMilliseconds(300));
daX.Duration = duration;
daY.Duration = duration;
//动画的主题是TranslateTransform变形,而非Button
this.tt.BeginAnimation(TranslateTransform.XProperty, daX);
this.tt.BeginAnimation(TranslateTransform.YProperty, daY);
}
每次单击按钮,按钮都会向窗体的右下角移动。
2.2 高级动画控制
使用From、To、By、Duration几个属性进行组合就可以制作很多不同效果的动画了,然而WPF动画系统提供的控制属性远不止这些。
属性 | 描述 | 应用举例 |
AccelerationRatio | 加速速率( 0.0 - 1.0)与DecelerationRatio之和不大于1.0 | 模拟汽车启动 |
DecelerationRatio | 减速速率( 0.0 - 1.0)与AccelerationRatio 之和不大于1.0 | 模拟汽车刹车 |
SpeedRatio | 动画实际播放速度与正常速度的比值 | 快进播放、慢动作 |
AutoReverse | 是否以相反的动画方式从终点值返回到起始值 | 倒退播放 |
RepeatBehavior | 动画的重复行为,取0为不播放,使用double类性值可控制循环播放次数,取Forever为永远循环 | 循环播放 |
BeginTime | 正式开始播放前的等待时间 | 多个动画之前的协同 |
EasingFunction | 缓冲式渐变 | 乒乓球弹跳效果 |
在这些属性中,EasingFunction是一个扩展性非常强的属性。它取值是IEasingFunction接口类型,而IEasingFunction派生类就有十几种,每个派生类都能产生不同的结束效果。比如BounceEase可以产生乒乓球弹跳的效果。
如果把前面的例子的代码改成这样:
private void Button_Click(object sender, RoutedEventArgs e)
{
DoubleAnimation daX = new DoubleAnimation();
DoubleAnimation daY = new DoubleAnimation();
//设置反弹
BounceEase be = new BounceEase();
be.Bounces = 3;//弹跳3次
be.Bounciness = 3;//弹性程度,值越大反弹越低
daY.EasingFunction = be;
//指定终点
Random r = new Random();
daX.To = r.NextDouble() * 300;
daY.To = r.NextDouble() * 300;
//指定时长
Duration duration = new Duration(TimeSpan.FromMilliseconds(2000));
daX.Duration = duration;
daY.Duration = duration;
//动画的主题是TranslateTransform变形,而非Button
this.tt.BeginAnimation(TranslateTransform.XProperty, daX);
this.tt.BeginAnimation(TranslateTransform.YProperty, daY);
}
产生乒乓球弹跳的效果。
2.3 关键帧动画
动画是UI元素属性连续改变所产生的视觉效果。属性每次细微的变化都会产生一个新的画面,每个新画面就称为一“帧”,帧的连续播放就产生动画的效果。关键帧动画允许程序员为一段动画设置几个里程碑,动画执行到里程碑所在的时间点时,被动画所控制的属性值也必须达到设定的值,这些时间线上的里程碑就是关键帧。
实例:
一个Button在单击后用900毫秒的时长从左上角移动到右下角,但移动路线不是直接移动而是走“Z”字形。
我们只需创建两个DoubleAnimationUsingKeyFrames实例,一个控制TranslateTransform的X属性,一个控制TranslateTransform的Y属性。每个DoubleAnimationUsingKeyFrames各拥有三个关键帧用于指明X或Y在三个时间点(两个拐点和终点)应该达到什么样的值。
程序的XAML代码如下:
<Grid>
<Button Width="60" Height="60" Content="Move" Click="Button_Click"
HorizontalAlignment="Left" VerticalAlignment="Top">
<Button.RenderTransform>
<TranslateTransform x:Name="tt" X="30" Y="30"/>
</Button.RenderTransform>
</Button>
</Grid>
Button的Click事件处理器代码如下:
private void Button_Click(object sender, RoutedEventArgs e)
{
DoubleAnimationUsingKeyFrames dakX = new DoubleAnimationUsingKeyFrames();
DoubleAnimationUsingKeyFrames dakY = new DoubleAnimationUsingKeyFrames();
// 设置动画总时长
dakX.Duration = new Duration(TimeSpan.FromMilliseconds(900));
dakY.Duration = new Duration(TimeSpan.FromMilliseconds(900));
// 创建关键帧
LinearDoubleKeyFrame x_kf_1 = new LinearDoubleKeyFrame();
LinearDoubleKeyFrame x_kf_2 = new LinearDoubleKeyFrame();
LinearDoubleKeyFrame x_kf_3 = new LinearDoubleKeyFrame();
//设置关键帧
x_kf_1.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300));
x_kf_1.Value = 200;
x_kf_2.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(600));
x_kf_2.Value = 0;
x_kf_3.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(900));
x_kf_3.Value = 200;
//添加关键帧
dakX.KeyFrames.Add(x_kf_1);
dakX.KeyFrames.Add(x_kf_2);
dakX.KeyFrames.Add(x_kf_3);
LinearDoubleKeyFrame y_kf_1 = new LinearDoubleKeyFrame();
LinearDoubleKeyFrame y_kf_2 = new LinearDoubleKeyFrame();
LinearDoubleKeyFrame y_kf_3 = new LinearDoubleKeyFrame();
y_kf_1.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300));
y_kf_1.Value = 0;
y_kf_2.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(600));
y_kf_2.Value = 180;
y_kf_3.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(900));
y_kf_3.Value = 180;
dakY.KeyFrames.Add(y_kf_1);
dakY.KeyFrames.Add(y_kf_2);
dakY.KeyFrames.Add(y_kf_3);
//执行动画
this.tt.BeginAnimation(TranslateTransform.XProperty, dakX);
this.tt.BeginAnimation(TranslateTransform.YProperty, dakY);
}
2.4 特殊的关键帧
DoubleAnimationUsingKeyFrames 的KeyFrames 属性的数据类型是DoubleKeyFrameCollection,此集合类可接收的类型为 DoubleKeyFrame。DoubleKeyFrame 是一个抽象类,它的所有派生类如下:
LinearDoubleKeyFrame:线性变化关键帧,目标属性值的变化时是直线性的、均匀的,即变化速率不变。
DiscreteDoubleKeyFrame:不连续变化关键帧,目标属性值的变化是跳跃性的、跃迁的。
SplineDoubleKeyFrame:样条函数式变化关键帧,目标属性的变化速率是一条贝塞尔曲线。
EasingDoubleKeyFrame:缓冲式变化关键帧,目标属性以某种缓冲形式变化。
4个派生类中最常用的是SplineDoubleKeyFrame。可以非常方面的制作非匀速动画,因为他使用一条贝塞尔曲线来控制目标属性值的变化速率。这条用于控制变化速率的贝塞尔曲线的起点是(0,0)和(1,1),分别映射着目标属性的变化起点和变化终点,意思是目标属性值由0%变化到100%。这条曲线的有两个控制点ControlPoint1和ControlPoint2,意思是曲线从起点出发先向ControlPoint1的方向前进、再向ControlPoint2的方向前进、最后到达终点,形成一条平滑的曲线。如果设置ControlPoint1和ControlPoint2的横纵坐标值相等,这是曲线成为一条直线,SplineDoubleKeyFrame和LinearDoubleKeyFrame是等价的。
下面是SplineDoubleKeyFrame的实例
程序的XAML代码如下:
<Grid>
<Button Width="60" Height="60" Content="Move" Click="Button_Click"
HorizontalAlignment="Left" VerticalAlignment="Top">
<Button.RenderTransform>
<TranslateTransform x:Name="tt" X="30" Y="30"/>
</Button.RenderTransform>
</Button>
</Grid>
Button的Click事件处理器代码如下:
private void Button_Click(object sender, RoutedEventArgs e)
{
// 创建动画
DoubleAnimationUsingKeyFrames dakX = new DoubleAnimationUsingKeyFrames();
dakX.Duration = new Duration(TimeSpan.FromMilliseconds(1000));
//创建、添加关键帧
SplineDoubleKeyFrame kf = new SplineDoubleKeyFrame();
kf.KeyTime = KeyTime.FromPercent(1);
kf.Value = 400;
//设置速率
KeySpline ks = new KeySpline();
ks.ControlPoint1 = new Point(0, 1);
ks.ControlPoint2 = new Point(1, 0);
kf.KeySpline = ks;
dakX.KeyFrames.Add(kf);
//执行动画
this.tt.BeginAnimation(TranslateTransform.XProperty, dakX);
}
关键帧动画会控制Button的位置变形、让Button横向移动。整个动画只有一个关键帧,这个关键帧使用的是SplineDoubleKeyFrame,变化速率控制曲线的两个控制点分别是(0,1)(1,0),目标属性会以“快-慢-快”的形式变化。
2.5 路径动画
如何让目标对象沿着一条给定的路径移动呢?答案是使用DoubleAnimationUsingPath类。DoubleAnimationUsingPath需要一个PathGeometry来指明移动路径,PathGeometry的数据信息可以用XAML的Path语法书写。PathGeometry的另一个重要属性是Source,Source属性的数据类型是PathAnimationSource枚举,枚举值可取X(关注曲线上每一点横坐标的变化)、Y(关注曲线上每一点纵坐标的变化)或Angle关注曲线上每一点处切线方向的变化。
实例:
让Button沿着一条贝塞尔曲线做波浪形运动。程序XAML代码如下:
<Grid>
<Grid x:Name="LayoutRoot">
<!--移动路径-->
<Grid.Resources>
<PathGeometry x:Key="movingPath"
Figures="M 0,150 C 300,-100 300,400 600,120"/>
</Grid.Resources>
<Button Content="Move" HorizontalAlignment="Left" VerticalAlignment="Top"
Width="80" Height="80" Click="Button_Click">
<Button.RenderTransform>
<TranslateTransform x:Name="tt" X="0" Y="0"/>
</Button.RenderTransform>
</Button>
</Grid>
</Grid>
Button的Click事件处理器代码如下:
private void Button_Click(object sender, RoutedEventArgs e)
{
// 查找资源
PathGeometry pg = this.LayoutRoot.FindResource("movingPath") as PathGeometry;
Duration duration = new Duration(TimeSpan.FromMilliseconds(600));// 设置动画时间
// 创建动画
DoubleAnimationUsingPath dapX = new DoubleAnimationUsingPath();
dapX.PathGeometry = pg;
dapX.Source = PathAnimationSource.X;
dapX.Duration = duration;
DoubleAnimationUsingPath dapY = new DoubleAnimationUsingPath();
dapY.PathGeometry = pg;
dapY.Source = PathAnimationSource.Y;
dapY.Duration = duration;
//设置来回循环效果
dapX.AutoReverse = true;
dapX.RepeatBehavior = RepeatBehavior.Forever;
dapY.AutoReverse = true;
dapY.RepeatBehavior = RepeatBehavior.Forever;
//执行动画
this.tt.BeginAnimation(TranslateTransform.XProperty, dapX);
this.tt.BeginAnimation(TranslateTransform.YProperty, dapY);
}
三、场景
场景就是并行执行的一组动画。
先是把一组独立的动画组织在一个Storyboard元素中、安排好他们的协作关系,然后制定哪个动画由哪个UI元素、哪个属性负责完成。Storyboard设计好后,你可以为他选择一个恰当的触发时机,比如按钮按下或下载开始时。一旦触发条件被满足,动画产经就会开始执行。
实例:
程序XAML代码如下:
<Grid Margin="6">
<!--布局控制-->
<Grid.RowDefinitions>
<RowDefinition Height="38"/>
<RowDefinition Height="38"/>
<RowDefinition Height="38"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="60"/>
</Grid.ColumnDefinitions>
<!--跑道红-->
<Border BorderBrush="Gray" BorderThickness="1" Grid.Row="0">
<Ellipse x:Name="ballR" Height="36" Width="36" Fill="Red"
HorizontalAlignment="Left">
<Ellipse.RenderTransform>
<TranslateTransform x:Name="ttR"/>
</Ellipse.RenderTransform>
</Ellipse>
</Border>
<!--跑道绿-->
<Border BorderBrush="Gray" BorderThickness="1,0,1,1" Grid.Row="1">
<Ellipse x:Name="ballG" Height="36" Width="36" Fill="LawnGreen"
HorizontalAlignment="Left">
<Ellipse.RenderTransform>
<TranslateTransform x:Name="ttG"/>
</Ellipse.RenderTransform>
</Ellipse>
</Border>
<!--跑道蓝-->
<Border BorderBrush="Gray" BorderThickness="1,0,1,1" Grid.Row="2">
<Ellipse x:Name="ballB" Height="36" Width="36" Fill="Blue"
HorizontalAlignment="Left">
<Ellipse.RenderTransform>
<TranslateTransform x:Name="ttB"/>
</Ellipse.RenderTransform>
</Ellipse>
</Border>
<!--按钮-->
<Button Content="Go!" Grid.Column="1" Grid.RowSpan="3">
<!--按钮触发-->
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard Duration="0:0:0.6">
<!--红色小球动画-->
<DoubleAnimation Duration="0:0:0.6" To="400"
Storyboard.TargetName="ttR"
Storyboard.TargetProperty="X"/>
<!--绿色小球动画-->
<DoubleAnimationUsingKeyFrames Duration="0:0:0.6"
Storyboard.TargetName="ttG" Storyboard.TargetProperty="X">
<SplineDoubleKeyFrame KeyTime="0:0:0.6" Value="400"
KeySpline="0,1,1,0"/>
</DoubleAnimationUsingKeyFrames>
<!--蓝色小球动画-->
<DoubleAnimationUsingKeyFrames Duration="0:0:0.6"
Storyboard.TargetName="ttB" Storyboard.TargetProperty="X">
<SplineDoubleKeyFrame KeyTime="0:0:0.6" Value="400"
KeySpline="1,0,0,1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
效果:
最后
以上就是文艺鲜花为你收集整理的WPF动画详解一、概述二、简单独立动画三、场景的全部内容,希望文章能够帮你解决WPF动画详解一、概述二、简单独立动画三、场景所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复