原文:《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列出了这些类型。

Table 8-2. Key-frame animation types

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.关键帧动画的更多相关文章

  1. 《Programming WPF》翻译 第8章 5.创建动画过程

    原文:<Programming WPF>翻译 第8章 5.创建动画过程 所有在这章使用xaml举例说明的技术,都可以在代码中使用,正如你希望的.可是,代码可以使用动画在某种程度上不可能在x ...

  2. 《Programming WPF》翻译 第9章 5.默认可视化

    原文:<Programming WPF>翻译 第9章 5.默认可视化 虽然为控件提供一个自定义外观的能力是有用的,开发者应该能够使用一个控件而不用必须提供自定义可视化.这个控件应该正好工作 ...

  3. 《Programming WPF》翻译 第9章 6.我们进行到哪里了?

    原文:<Programming WPF>翻译 第9章 6.我们进行到哪里了? 只有当任何内嵌控件都没有提供你需要的底层行为时,你将要写一个自定义控件.当你写一个自定义控件,你将要使用到依赖 ...

  4. 《Programming WPF》翻译 第9章 4.模板

    原文:<Programming WPF>翻译 第9章 4.模板 对一个自定义元素最后的设计考虑是,它是如何连接其可视化的.如果一个元素直接从FrameworkElement中派生,这将会适 ...

  5. 《Programming WPF》翻译 第9章 3.自定义功能

    原文:<Programming WPF>翻译 第9章 3.自定义功能 一旦你挑选好一个基类,你将要为你的控件设计一个API.大部分WPF元素提供属性暴露了多数功能,事件,命令,因为他们从框 ...

  6. 《Programming WPF》翻译 第9章 2.选择一个基类

    原文:<Programming WPF>翻译 第9章 2.选择一个基类 WPF提供了很多类,当创建一个自定义元素时,你可以从这些类中派生.图9-1显示了一组可能作为类--可能是合适的基类, ...

  7. 《Programming WPF》翻译 第9章 1.自定义控件基础

    原文:<Programming WPF>翻译 第9章 1.自定义控件基础 在写一个自定义控件之前,你需要问的第一个问题是,我真的需要一个自定义控件吗?一个写自定义控件的主要原因是为了用户界 ...

  8. 《Programming WPF》翻译 第8章 6.我们进行到哪里了?

    原文:<Programming WPF>翻译 第8章 6.我们进行到哪里了? 动画可以增强应用程序的交互感.它有利于更平滑的转换--当条目出现或消失的时候.它应该,当然,被用于体验和重新着 ...

  9. 《Programming WPF》翻译 第8章 3.Storyboard

    原文:<Programming WPF>翻译 第8章 3.Storyboard Storyboard是动画的集合.如果你使用了标记,所有的动画必须要被定义在一个Storyboard中.(在 ...

随机推荐

  1. TaintDroid:智能手机监控实时隐私信息流跟踪系统(四)

    6      应用程序研究 款流行的应用程序是怎么使用用户敏感数据的.选取的应用程序可以根据相应的权限通过Internet获得各种各样的用户数据.我们研究发现三分之二的这些数据暴露了用户详细的地理位置 ...

  2. cocos2dx lua 加密

    cocos2dx-lua项目发布时,为了保护lua源码,需要对lua进行加密.通常分为两种方式:加密文件和编译为字节码. 1.加密文件 前提是你不用luajit,而使用lua.这样这种方法是真正加密, ...

  3. <php>Ajax基本格式

    <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8&quo ...

  4. 第24讲 UI_布局 之帧布局 表格布局 绝对布局

    第24讲 UI_布局 之帧布局 表格布局 绝对布局 3. FrameLayout(帧布局) 帧布局是从屏幕的左上角(0,0)坐标开始布局,多个组件层叠排序,后一个组件总会将前一个组件所覆盖,除非最后一 ...

  5. C/C++经典面试题目

    1.关于动态申请内存 答:内存分配方式三种: (1)从静态存储区域分配:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.全局变量,static变量. (2)在栈上创建:在执行函数 ...

  6. XSS完全解决方案

    xss 为什么不能阻止用户输入不安全数据 比如用户想发一篇标题的文章 1+1>2吗? 为什么不在数据库存的时候就处理好或者接口里处理好 1<2 会被转义为 1<2,放到html中确实 ...

  7. JavaScript 精髓整理篇之一(对象篇)postby:http://zhutty.cnblogs.com

    废话篇头: 由于工作关系,所以写博文的时间有那么点~~,其实是输入法太懒了,都是输入法的错~~ 这一系列的博客将总结所有关于JavaScript语言的精髓,适合0基础到大师级别人物阅读. <Ja ...

  8. Android 之 Shape (圆角输入框)

    1 简介 本文主要介绍通过 shape 来设置 EditText 的圆角.   2 shape 的设置   shape_life_search.xml 放在 res/drawable 文件夹内 < ...

  9. Javascript进阶篇——(DOM—节点---插入、删除和替换元素、创建元素、创建文本节点)—笔记整理

    插入节点appendChild()在指定节点的最后一个子节点列表之后添加一个新的子节点.语法: appendChild(newnode) //参数: //newnode:指定追加的节点. 为ul添加一 ...

  10. 客户Oracle数据库在插入数据的时候报超出最大长度的错误(规避风险)

    背景: 项目使用oracle数据,在开发环境测试一些正常.项目部署到客户的服务器上后,系统在添加数据的时候报错.输出错误信息,发现是“超出最大长度”的异常. 但是按照数据库的设计,添加的数据应该在允许 ...