《Programming WPF》翻译 第8章 4.关键帧动画
原文:《Programming WPF》翻译 第8章 4.关键帧动画
到目前为止,我们只看到简单的点到点的动画。我们使用了To和From属性或者By属性来设计动画——相对于当前的属性值。这很适合简单的动画,但是我们可以构造序列来创建更复杂的动画,这可能是非常麻烦的。幸运的是,这是没有必要的。WPF提供了动画对象,允许我们详细指出一系列时间和值。
在影视中传统的动画中,这是普通的开始——通过绘制最重要的动画步骤。这些关键帧定义了场景的基本流程,捕获了它的最重要的点。只要一旦这些关键帧是满意的,是保留的帧绘图。这些关键帧之间的图像并不要求非常创造性的输入,它们只是简单的打算添加进去,从一个关键帧到另一个。WPF优化了同样的概念。你可以考虑简单的From和To方法——等价于提供两个关键帧,一个“before”帧和一个“after”帧——WPF会为你添加这两个帧。关键帧动画简单的扩展了多个帧的概念。
作为最简单的动画类型,关键帧仍然一次性为属性设定目标。因此它们并不与传统动画中关键帧一样,每一帧组成了整个的绘图。你不能提供两个绘图并告诉WPF从一个变换到另一个。
关键帧动画类型使用了命名装换TypeAnimationUsingKeyFrames。示例8-24显示了一个简单的动画:一个弹起的矩形,使用到了DoubleAnimationUsingKeyFrames。
示例8-24
<Window Text="Key Frames" Width="850" Height="300"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005">

<Window.Storyboards>
<SetterTimeline TargetName="rect" Path="(Canvas.Left)"
RepeatBehavior="Forever" AutoReverse="True">
<DoubleAnimation From="0" To="800" Duration="0:0:10" />
</SetterTimeline>
<SetterTimeline TargetName="rect" Path="(Canvas.Top)">
<DoubleAnimationUsingKeyFrames Duration="0:0:2"
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>
</SetterTimeline>
</Window.Storyboards>
<Canvas>
<Rectangle x:Name="rect" Fill="Red" Width="20" Height="20" />
</Canvas>
</Window>这里有两个timeline。第一个移动矩形从左到右,使用常规的DoubleAnimation,第二个通过使用DoubleAnimationUsingKeyFrames控制了垂直的位置。这控制了5个帧,详细指出了矩形的需要的垂直位置,在半秒的时间内。如图8-12所示,这些关键帧显示了这个矩形,在它的跳动的顶部和底部,伴随着中途的点比中间点稍微高一点,指出一段时间的速度渐变。WPF为我们在这些位置之间加入了新元素。
图8-12

示例8-24中每个关键帧的值都使用LinearDoubleKeyFrame详细指出。这说明了使用了线形添写。改变的速度是介于两个帧之间的常量。这就引起了运动并不是特别平滑的。这个矩形在它下降时提高速度,而速度上的改变发生在可见的“阶段”——从动画的一幕到下一幕。我们可以减少这种影响,通过添加更多的关键帧,但是这里有一条更容易的方式。不是图8-13中左边显示的简单线性插值,而是获取一个曲线插值如右边显示,提高了平滑度,而不需要添加更多的关键帧。
图8-13

为了在我们想要的动画速度上获取更平滑的改动,我们可以使用SplineDoubleKeyFrame。带有一个样条关键帧,一条贝塞尔曲线详细指出了动画值是应该如何改变的。可是,这种曲线使用的方式并不是完全直接的。正如我们在第7章看到的,贝塞尔曲线可以用于定义曲线形状。可是,使用动画,我们不能简单地定义路径。一个点沿示例中的贝塞尔曲线而行。这条曲线是一个二维的形状,但是这个动画对象仅修改了y轴,这意味着它只在一个维度上产生影响。(记得示例8-24使用了2个SetterTimeline元素,每个都对应一个维度。)
代替以定义点的路径,贝塞尔曲线在一个样条关键帧上定义了一个数学函数的形式。这个函数把它的输入理解为关键帧的流逝时间的比例。作为输出,它提供了一个数字,指出之前的和当前的值混合在一起的比例。这条曲线总是从(0,0)移动到(1,1),但是你定位这两个控制点,决定了它的形状在这些极限之间。使用关键帧的KeySpline属性设置这些值。
图8-14显示了3个动画样条的示例,控制点标记在小矩形上。记得这些曲线简单的决定了动画前进的速度。第一个“曲线”是一条直线,意味着这个动画以常速前进。这等价于一个LinearDoubleKeyFrame。第二条曲线指出了动画开始缓慢而后加速。第三条曲线显示了动画开始迅速而后减速到停止。
图8-14

示例8-25是示例8-24的对关键帧的修改版本。这个动画传递了同样的关键帧值,但是使用样条来指出动画的速度应该逐渐改变。这使得这个动画感觉很平滑,而不需要添加更多的关键帧。
示例8-25
<SetterTimeline TargetName="rect" Path="(Canvas.Top)">
<DoubleAnimationUsingKeyFrames Duration="0:0:2" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames.KeyFrames>
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0" />
<SplineDoubleKeyFrame Value="50" KeyTime="0:0:0.5"
KeySpline="0.4,0 0.75,0.75" />
<SplineDoubleKeyFrame Value="200" KeyTime="0:0:1"
KeySpline="0.2,0.2 1,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"
KeySpline="0.25,0.25 0.6,1" />
</DoubleAnimationUsingKeyFrames
.KeyFrames>
</DoubleAnimationUsingKeyFrames>
</SetterTimeline>第一帧仍然使用LinearDoubleKeyFrame,因为这里没有“before”帧以进行插值。两个“downward”关键帧使用了曲线形状——类似于图8-14中间的那个。这导致了这个动画开始缓慢然后加速,正如你希望的在一个下落对象的动画中。两个“upward”关键帧使用了曲线形状——类似于图8-14右边的那个。这导致了这个动画逐渐缓慢直到这个对象到达顶部。这就提供了一个更有力的可视化近似:关于一个真实的对象是如何运动的。
这里还有一种可利用的的插值样式:四点插值细分算法。如果你使用了这样一个关键帧,WPF根本不会真正地“插值”。它会突然跳到详细指定的值。这就易于引进中断到你的动画中,如果必要。
注意到,WPF提供了关键帧的版本——大多数动画类型都支持它,不仅是Double类型,表8-2列出了这些类型。
|
BooleanAnimationUsingKeyFrames |
PointAnimationUsingKeyFrames |
|
ByteAnimationUsingKeyFrames |
Rect3DAnimationUsingKeyFrames |
|
CharAnimationUsingKeyFrames |
RectAnimationUsingKeyFrames |
|
ColorAnimationUsingKeyFrames |
Rotation3DAnimationUsingKeyFrames |
|
DecimalAnimationUsingKeyFrames |
SingleAnimationUsingKeyFrames |
|
DoubleAnimationUsingKeyFrames |
Size3DAnimationUsingKeyFrames |
|
Int16AnimationUsingKeyFrames |
SizeAnimationUsingKeyFrames |
|
Int32AnimationUsingKeyFrames |
StringAnimationUsingKeyFrames |
|
Int64AnimationUsingKeyFrames |
ThicknessAnimationUsingKeyFrames |
|
MatrixAnimationUsingKeyFrames |
Vector3DAnimationUsingKeyFrames |
|
Point3DAnimationUsingKeyFrames |
VectorAnimationUsingKeyFrames |
《Programming WPF》翻译 第8章 4.关键帧动画的更多相关文章
- 《Programming WPF》翻译 第8章 5.创建动画过程
原文:<Programming WPF>翻译 第8章 5.创建动画过程 所有在这章使用xaml举例说明的技术,都可以在代码中使用,正如你希望的.可是,代码可以使用动画在某种程度上不可能在x ...
- 《Programming WPF》翻译 第9章 5.默认可视化
原文:<Programming WPF>翻译 第9章 5.默认可视化 虽然为控件提供一个自定义外观的能力是有用的,开发者应该能够使用一个控件而不用必须提供自定义可视化.这个控件应该正好工作 ...
- 《Programming WPF》翻译 第9章 6.我们进行到哪里了?
原文:<Programming WPF>翻译 第9章 6.我们进行到哪里了? 只有当任何内嵌控件都没有提供你需要的底层行为时,你将要写一个自定义控件.当你写一个自定义控件,你将要使用到依赖 ...
- 《Programming WPF》翻译 第9章 4.模板
原文:<Programming WPF>翻译 第9章 4.模板 对一个自定义元素最后的设计考虑是,它是如何连接其可视化的.如果一个元素直接从FrameworkElement中派生,这将会适 ...
- 《Programming WPF》翻译 第9章 3.自定义功能
原文:<Programming WPF>翻译 第9章 3.自定义功能 一旦你挑选好一个基类,你将要为你的控件设计一个API.大部分WPF元素提供属性暴露了多数功能,事件,命令,因为他们从框 ...
- 《Programming WPF》翻译 第9章 2.选择一个基类
原文:<Programming WPF>翻译 第9章 2.选择一个基类 WPF提供了很多类,当创建一个自定义元素时,你可以从这些类中派生.图9-1显示了一组可能作为类--可能是合适的基类, ...
- 《Programming WPF》翻译 第9章 1.自定义控件基础
原文:<Programming WPF>翻译 第9章 1.自定义控件基础 在写一个自定义控件之前,你需要问的第一个问题是,我真的需要一个自定义控件吗?一个写自定义控件的主要原因是为了用户界 ...
- 《Programming WPF》翻译 第8章 6.我们进行到哪里了?
原文:<Programming WPF>翻译 第8章 6.我们进行到哪里了? 动画可以增强应用程序的交互感.它有利于更平滑的转换--当条目出现或消失的时候.它应该,当然,被用于体验和重新着 ...
- 《Programming WPF》翻译 第8章 3.Storyboard
原文:<Programming WPF>翻译 第8章 3.Storyboard Storyboard是动画的集合.如果你使用了标记,所有的动画必须要被定义在一个Storyboard中.(在 ...
随机推荐
- Cmake编译成静态库
To build OpenCV as static library you need to set BUILD_SHARED_LIBS flag to false/off: cmake -DBUILD ...
- logstash 发送zabbix告警
<pre name="code" class="html">[elk@dr-mysql01 test]$ cat t1.conf input { s ...
- Linux Top使用说明
运行top后,按P键就按CPU排序,按M键就按内存排序 P – 以 CPU 占用率大小的顺序排列进程列表 M – 以内存占用率大小的顺序排列进程列表 在系统维护的过程中,随时可能有需要查看 CPU 使 ...
- 按每k个结点反转链表
//按每k个结点反转链表 Node* turn_k(Node* head,int n,int k) { Node* p=head; ;t<k;t++) p=p->next; //为了获取最 ...
- c语言筛选质数
#include <stdio.h> #include <stdlib.h> #include <math.h> int isit(int num) { int i ...
- 第26讲 对话框AlertDialog的自定义实现
第26讲对话框AlertDialog的自定义实现 比如我们在开发过长当中,要通过介绍系统发送的一个广播弹出一个dialog.但是dialog必需是基于activity才能呈现出来,如果没有activi ...
- Html5学习笔记(一)
一:常见标签类型 块级标签 特点:1.独占一行 2,可以随时设置w,h 2.行内标签(内联) 特点: 1.多个行内标签能同时显示在一行 2.w.h取决于内容的尺寸() 3.行内-块级标签 特点 ...
- mysql下用户和密码生成管理
应用上线,涉及到用户名和密码管理,随着上线应用的增加,用户名和密码的管理设置成为一个问题.还要对用户赋权,于是想着写一个脚本来管理,看到同事写的一个脚本,满足需求.思路大致是字母替换为数字,账号根据库 ...
- leetcode:Minimum Path Sum(路线上元素和的最小值)【面试算法题】
题目: Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right w ...
- oracle函数之replace
replace('将要更改的字符串','被替换掉的字符串','替换字符串'): ','****') from tmall_tcmessage; 输出为 '158****3367'