《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
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
<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中.(在 ...
随机推荐
- TaintDroid:智能手机监控实时隐私信息流跟踪系统(四)
6 应用程序研究 款流行的应用程序是怎么使用用户敏感数据的.选取的应用程序可以根据相应的权限通过Internet获得各种各样的用户数据.我们研究发现三分之二的这些数据暴露了用户详细的地理位置 ...
- cocos2dx lua 加密
cocos2dx-lua项目发布时,为了保护lua源码,需要对lua进行加密.通常分为两种方式:加密文件和编译为字节码. 1.加密文件 前提是你不用luajit,而使用lua.这样这种方法是真正加密, ...
- <php>Ajax基本格式
<head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8&quo ...
- 第24讲 UI_布局 之帧布局 表格布局 绝对布局
第24讲 UI_布局 之帧布局 表格布局 绝对布局 3. FrameLayout(帧布局) 帧布局是从屏幕的左上角(0,0)坐标开始布局,多个组件层叠排序,后一个组件总会将前一个组件所覆盖,除非最后一 ...
- C/C++经典面试题目
1.关于动态申请内存 答:内存分配方式三种: (1)从静态存储区域分配:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.全局变量,static变量. (2)在栈上创建:在执行函数 ...
- XSS完全解决方案
xss 为什么不能阻止用户输入不安全数据 比如用户想发一篇标题的文章 1+1>2吗? 为什么不在数据库存的时候就处理好或者接口里处理好 1<2 会被转义为 1<2,放到html中确实 ...
- JavaScript 精髓整理篇之一(对象篇)postby:http://zhutty.cnblogs.com
废话篇头: 由于工作关系,所以写博文的时间有那么点~~,其实是输入法太懒了,都是输入法的错~~ 这一系列的博客将总结所有关于JavaScript语言的精髓,适合0基础到大师级别人物阅读. <Ja ...
- Android 之 Shape (圆角输入框)
1 简介 本文主要介绍通过 shape 来设置 EditText 的圆角. 2 shape 的设置 shape_life_search.xml 放在 res/drawable 文件夹内 < ...
- Javascript进阶篇——(DOM—节点---插入、删除和替换元素、创建元素、创建文本节点)—笔记整理
插入节点appendChild()在指定节点的最后一个子节点列表之后添加一个新的子节点.语法: appendChild(newnode) //参数: //newnode:指定追加的节点. 为ul添加一 ...
- 客户Oracle数据库在插入数据的时候报超出最大长度的错误(规避风险)
背景: 项目使用oracle数据,在开发环境测试一些正常.项目部署到客户的服务器上后,系统在添加数据的时候报错.输出错误信息,发现是“超出最大长度”的异常. 但是按照数据库的设计,添加的数据应该在允许 ...