21.2.2 使用代码创建动画(1)
您已经学习过,大多数普通的动画技术是线性插值动画,这种技术平滑地从开始点到结束点修改属性值。例如,如果将开始数值设置为1,并且将结束数值设置为10,属性可能会被从1快速地改变到1.1、1.2、1.3等等,直到数值达到10。
现在,您可能会好奇当执行插值时,WPF如何决定使用的步长。幸运的是,这个细节是自动进行的。WPF使用它所需要的步长以确保在当前配置的帧速率下得到平滑的动画。标准的帧速率是60帧/秒(在本章的后面将会学习如何改变这一细节)。换句话说,每1/60秒WPF就会计算所有应用了动画的数值,并更新相应的属性。
使用动画最简单的方式是实例化一个在前面列出的动画类,并配置该实例,然后使用希望修改的元素的BeginAnimation( )方法。所有的WPF元素都继承了BeginAnimation( )方法,该方法是IAnimationable接口的一部分,它来自UIElement基类。其他实现了IAnimationable接口的类包括ContentElement类(文档流内容的基类)和Visual3D类(3D可视化对象的基类)。
注意:
这并不是最常用的方法-- 在大多数情况下,将会使用XAML声明式地创建动画,就像在后面的21.3节中描述的那样。然而,使用XAML会牵扯更多内容,因为需要另外一个对象(称为故事板)为合适的属性连接动画。在特定的情况下,当需要使用复杂的逻辑为动画决定开始值和结束值时,基于代码的动画也是很有用的。
图21-1显示了一个非常简单的、增加按钮宽度的动画。当单击该按钮时,WPF平滑地扩展按钮的两个侧边直到充满窗口。
|
| (点击查看大图)图21-1 具有动画的按钮 |
|
| (点击查看大图)图21-1 (续) |
- DoubleAnimation widthAnimation = new DoubleAnimation();
- widthAnimation.From = 160;
- widthAnimation.To = this.Width - 30;
- widthAnimation.Duration = TimeSpan.FromSeconds(5);
- cmdGrow.BeginAnimation(Button.WidthProperty, widthAnimation);
任何使用线性插值的动画最少需要三个细节:开始值(From)、结束值(To)和整个动画执行的时间(Duration)。在这个示例中,结束值基于包含按钮的窗口的当前宽度。使用插值的所有动画类都提供了这三个属性。
From属性、To属性以及Duration属性看起来很简单,但是应当注意它们的几个重要的细节。在后面的几部分将会更深入地分析这些属性。
1. From属性
From值是Width属性的开始数值。如果多次单击按钮,每次单击时都会将Width属性重新设置为160,并且重新开始动画。即使当动画正在运行时也是如此。
注意:
这个示例提供了另外一个WPF动画细节,即每个依赖项属性每次只能响应一个动画。如果开始第二个动画,第一个动画就会自动放弃。
在许多情况下,可能不希望动画从最初的From值开始。这有如下两个常见的原因:
创建一个能够被触发多次,并且逐次累加效果的动画。例如,可能希望创建一个每次单击时都增大一点的按钮。
创建可能相互重叠的动画。例如,可以使用MouseEnter事件触发一个扩展按钮的动画,并使用MouseLeave事件触发一个将按钮缩小为原尺寸的互补动画(这通常被称为"鱼眼"效果)。如果快速连续地将鼠标多次移动到这种按钮上并移开,每个新动画就会打断上一个动画,导致按钮"跳"回到由From属性设置的值。
当前示例属于第二种情况。如果当按钮正在增大时单击按钮,按钮的宽度就会被重新设置为160个像素-- 这可能会出现抖动效果。为了改正这个问题,只需要删除设置Form属性的代码即可:
- DoubleAnimation widthAnimation = new DoubleAnimation();
- widthAnimation.To = this.Width - 30;
- widthAnimation.Duration = TimeSpan.FromSeconds(5);
- cmdGrow.BeginAnimation(Button.WidthProperty, widthAnimation);
现在有一个问题。为了使用这种技术,动画的属性必须有一个设置值。在这个示例中,这意味着按钮必须有一个硬编码的宽度(不管是在按钮标签中直接定义的,还是通过样式设置器应用的)。问题是在许多布局包容器中,通常不能指定一个宽度并且让包容器根据元素的对齐方式进行控制。对于这种情况,元素使用默认宽度,它是特殊的DoubleNaN数值(在此NaN代表"不是一个数字(not a number)")。对于具有这种数值的属性不能使用线性插值生成动画。
那么,解决方法是什么呢?在许多情况下,答案是硬编码按钮的宽度。正如将要介绍的,动画经常需要更加精确地控制元素的尺寸和位置。实际上,对于能够应用动画的内容,最常用的布局包容器是Canvas控件,因为Canvas控件能够比较容易地移动内容(可能相互重叠)以及改变内容的尺寸。Canvas控件还是最轻量级的布局包容器,因为当一个属性,如Width属性,发生变化时不需要额外的布局工作。
在当前的示例中,还有另外一种选择。可以使用ActualWidth属性检索按钮的当前宽度值,该属性给出的是按钮当前渲染的宽度。不能为ActualWidht属性应用动画(它是只读的),但是可以使用该属性设置动画的From属性:
- widthAnimation.From = cmdGrow.ActualWidth;
【责任编辑:云霞 TEL:(010)68476606】
| 回书目 上一节 下一节 |




























