【WPF学习】第五十一章 动画缓动

线性动画的一个缺点是,它通常让人觉得很机械且不能够自然。相比而言,高级的用户界面具有模拟真实世界系统的动画效果。例如,可能使用具有触觉的下压按钮,当单击时按钮快速弹回,但是当没有进行操作时它们会慢慢地停下来,创建真正移动的错觉。或者,可能使用类似Windows操作系统的最大化和最小化效果,当窗口解决最终尺寸时窗口扩展或收缩的速度会加速。这些细节十分细微,当它们的实现比较完美时可能不会注意到它们。然而,几乎总会注意到,粗糙的缺少这些更细微特征的动画会给人留下笨拙的印象。改进动画并创建更趋自然的动画的秘诀是改变变化速率。不是创建以固定不变的速率改变的属性的动画,而是需要设计根据某种方式加速或减速的动画。WPF提供了几种选择。基于帧的动画和关键帧动画,这两种技术都提供了更精细地控制动画的能力。但实现更趋自然的动画的最简单方法是使用预置的缓动函数(easing function)。当使用缓动函数时,仍可通过指定开始和结束属性值以常规的方式定义动画。但为了附加这些细节,需要添加预先编写好的修改动画过场的数学函数,使动画在不同的点加速或减速。一、使用缓动函数动画缓动的最大优点是,相对于其他方法,如基于帧的动画和关键帧动画,这种方法需要的工作少很多。为使用动画缓动,使用某个缓动函数类(继承自EasingFunctionBase的类)的实例设置动画对象的EasingFunction属性。通常需要设置缓动函数的几个属性,并且为了得到所希望的效果,可能必须使用不同的设置,但不需要编写代码并且只需很少的XAML。例如,分析下面给出的两个动画,这两个动画用于按钮。当用户将鼠标移到按钮上时,使用一小段代码调用growStoryboard动画,将按钮拉伸到400单位。当用户移动鼠标使其离开按钮时,按钮收缩到其正常尺寸。<Storyboard x:Name="growStoryboard"> <DoubleAnimation Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Width" To="400" Duration="0:0:1.5"></DoubleAnimation></Storyboard><Storyboard x:Name="revertStoryboard"> <DoubleAnimation Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Width" Duration="0:0:3"></DoubleAnimation></Storyboard>现在,动画使用线性插值,这意味着按钮以恒定的机械性的速度增长和收缩。为得到更趋自然的效果,可使用缓动函数。下面的示例添加了名为ElasticEase的缓动函数。最终效果是按钮弹跳出其完整宽度,然后迅速弹回一点,接着在此摆动超出其完整尺寸(但比上一次稍少一点),再以稍小的幅度迅速弹回,等等,随着运动的减弱不断地重复这一跳动模式。之后逐渐进入缓和的10此振荡。Oscillations属性控制最终跳动的次数。ElasticEase类提供了另一个在该例中没有使用的属性:Springiness。该属性的值越大,后续的每个振荡静止得越快(默认值是3)。<Storyboard x:Name="growStoryboard"> <DoubleAnimation Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Width" To="400" Duration="0:0:1.5"> <DoubleAnimation.EasingFunction> <ElasticEase Oscillations="10" EasingMode="EaseOut"></ElasticEase> </DoubleAnimation.EasingFunction> </DoubleAnimation></Storyboard>为真正理解该标记和前面缓动函数的示例之间的区别,需要试一下该动画。变化是显著的。仅时候用一行XAML,就将一个简单的动画从业务的效果修改为精致美观的效果,在专业的应用程序中会感觉到这种精致效果。二、在动画开始时应用缓动与动画结束时应用缓动在继续分析不同的缓动函数前,理解缓动函数的应用时机很很重要的。所有缓动函数类都继承自EasingFunctionBase类,并且继承了EasingMode属性。该属性具有三个可能值:EaseIn(该值意味着在动画开始时应用缓动效果)、EaseOut(该值意味着在动画结束时应用缓动效果)、EaseInOut(该值意味着在动画开始和结束时应用缓动效果——将EaseIn用于动画的前半部分,将EaseOut用于动画的后半部分)。在上面的示例中,growStoryboard中的动画使用EaseOut模式。因此,逐渐减弱的跳动序列发生于动画的末尾。如果将ElasticEase函数的缓动模式切换为EaseIn,跳动将在动画的开始部分发生。按钮手势使其宽度比开始值更小一点,然后扩展宽度使其超过开始值,继而再稍多地收缩回一点,持续这种模式以逐渐地增加振荡直到自由振荡并扩展剩余的部分(使用ElasticEase.Osicillations属性控制振荡次数)。最后,EaseInOut模式创建更新颖的效果,在动画的前半部分是振荡动画的开始,接下来在动画的后半部分是振荡动画的结束。三、缓动函数类WPF提供了11个缓动函数类,所有这些类都位于熟悉的System.Windows.Media.Animation名称控件中。下表描述了所有缓动函数类,并列出了它们的重要属性。请记住,每个缓动函数类还提供了EasingMode属性,用于控制是影响动画的开始(EaseIn)、是影响动画的结束(EaseOut)还是同时影响动画的开始和结束(EaseInOut)。表 缓动函数名    称   说     明   属    性BackEase当使用EaseIn模式应用该缓动函数时,在动画开始之前来回动画。当使用EaseOut模式应用该缓动函数时,允许动画稍微超越然后拉回Amplitude属性决定了拉回和超越的量。默认值是1,可减少该属性值(大于0的任何值)以缩减效果,或增加该属性值以放大效果ElasticEase当使用EaseOut模式应用缓动函数时,使动画超越其最大值并前后摆动,逐渐减慢。当使用EaseIn模式应用该缓动函数时,动画在其开始值周围前后摆动,逐渐增加Oscillations属性控制动画前后摆动的次数(默认值是3),Springiness属性控制振荡增加或减弱的速度(默认值是3)BounceEase执行与ElasticEase缓动函数类似的效果,只是弹跳永远不会超越初始值或最终值Bounce属性控制动画回跳的次数(默认值是2),Bounciness属性决定弹跳增加或减弱的速度(默认值是2)CircleEase使用圆函数加速(使用EaseIn模式)或减速(使用EaseOut模式)动画无CubicEase使用基于时间立方的函数加速(使用EaseIn模式)动画。其效果与CircleEase类似,但是加速过程更缓和无QuadraticEase使用基于时间平分的函数加速(使用EaseIn模式)或减速(使用EaseOut模式)动画。效果与CubicEase类似,但加速过程更缓和无QuarticEase使用基于时间4次方的函数加速(使用EaseIn模式)或减速(使用EaseOut模式)动画。效果和CubicEase以及QuadraticEase类似,但加速过程更明显无QuinticEase使用基于时间5次方的函数加速(使用EaseIn模式)或减速(使用EaseOut模式)动画。效果和CubicEase、QuadraticEase以及QuarticEase类似,但是加速过程更明显无SineEase使用包含正弦计算的函数加速(使用EaseIn模式)或减速(使用EaseOut模式)动画。加速非常缓和,并且相对于其他各种缓动函数更接近线性插值无PowerEase使用幂函数f(t)=t^p加速(使用EaseIn模式)或减速(使用EaseOut模式)动画。根据为指数p使用的值,可复制Cubic、QuadraticEase、QuarticEase以及QuinticEasePower属性用于设置公式中的指数。将该属性设置为2会复制QuadraticEase的效果,设置为3会复制CubicEase的效果。设置为4会复制QuarticEase的效果。设置为5会复制QuinticEase效果,或选择其他不同值,默认值是2ExponentialEase使用指数函数f(t)=(e(at)-1)/(e(a)-1)加速(使用EaseIn模式)或减速(使用EaseOut模式)动画Exponent属性用于设置指数(默认值是2)许多缓动函数提供了类似但隐约不同的效果。为成功地使用动画缓动,需要决定使用哪个缓动函数,以及如何进行配置。通常,这个过程需要一点试错的体验。有两个资源可提供帮助。首先,WPF文档为每个缓动函数的行为提供了插图示例,显示动画如何随着时间修改属性值。查看这些插图是理解缓动函数作用的好方法。其次,Microsoft提供了几个范例程序,可使用这些范例播放不同的缓动函数,并尝试不同的属性值。最方便的范例之一是Silverlight应用程序。四、创建自定义缓动函数通过从EasingFunctionBase继承自己的类,并重载EaseInCore()和CreateInstanceCore()方法,可创建自定义缓动效果。这是一个非常专业的技术,因为大部分开发人员能通过配置标准的缓动函数来获得所希望的效果。然而,如果确实决定创建自定义缓动函数,将发现该过出奇简单。需要编写的几乎所有逻辑都在EaseInCore()方法中运行。该方法接受一个规范化的时间值——本质上,是表示动画进度的从0到1之间的值。当动画开始时,规范化得时间值是0。它从该点开始增加,直到在动画结束点达到1。protected override double EaseInCore(double normalizedTime){...}在动画运行期间,每次更新动画的值时WPF都会调用EaseInCore()方法。确切的调用频率取决于动画的帧率,但可以预期每秒调用EaseInCore()方法的次数接近60。为执行缓动,EaseInCore()方法采用规范化的时间值,并以某种方式对其进行调整。EaseInCore()方法返回的调整后的值,随后被用于调整动画的进度。例如,如果EaseInCore()方法返回0,动画被返回到其开始点。如果EaseInCore()方法返回1,动画跳到其结束点。然而,EaseInCore()方法的返回值并不局限于这一范围——例如,可返回1.5以使动画过渡运行自身50%。已经看到过用于缓动函数(如ElasticEase)的这类效果。下面给出的EaseInCore()方法版本根本不执行任何工作。该版本返回规范化的时间值,意味着动画将均匀展开,就像是没有缓动。protected override double EaseInCore(double normalizedTime){ return normalizedTime; }下面的EaseInCore()方法版本通过计算规范化时间值得立方,复制CubicEase函数的效果。因为规范化的时间值是小数,其立方值是更小的小数;所以该方法的效果是最初减慢动作动画,并当规范化的时间值(及其立方值)解决与1时导致动画加速。protected override double EaseInCore(double normalizedTime) { return Math.Pow(normalizedTime, 3); }最后,下面是一个执行更有趣内容的自定义缓动函数——以一定的随机量便宜规范化的时间值,导致分散的抖动效果。可使用提供的Jitter依赖性属性(在一个较小的范围内)调整抖动的幅度,该属性接受从0到2000之间的数值。public class RandomJitterEase : EasingFunctionBase { // Store a random number generator. private Random rand = new Random(); protected override double EaseInCore(double normalizedTime) { //To see the values add code like this: //System.Diagnostics.Debug.WriteLine(...); // Make sure there's no jitter in the final value. if (normalizedTime == 1) return 1; // Offset the value by a random amount. return Math.Abs(normalizedTime - (double)rand.Next(0, 10) / (2010 - Jitter)); } public int Jitter { get { return (int)GetValue(JitterProperty); } set { SetValue(JitterProperty, value); } } public static readonly DependencyProperty JitterProperty = DependencyProperty.Register("Jitter", typeof(int), typeof(RandomJitterEase), new UIPropertyMetadata(1000), new ValidateValueCallback(ValidateJitter)); private static bool ValidateJitter(object value) { int jitterValue = (int)value; return ((jitterValue <= 2000) && (jitterValue >= 0)); } // This required override simply provides a live instance of your easing function. protected override Freezable CreateInstanceCore() { return new RandomJitterEase(); } }下面是缓动函数在XAML中使用的示例:<Window x:Class="Animation.CustomEasingFunction" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Animation" Title="CustomEasingFunction" Height="300" Width="600"> <Window.Triggers> <EventTrigger RoutedEvent="Window.Loaded"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Canvas.Left)" To="500" Duration="0:0:10"> </DoubleAnimation> <DoubleAnimation Storyboard.TargetName="ellipse2" Storyboard.TargetProperty="(Canvas.Left)" To="500" Duration="0:0:10"> <DoubleAnimation.EasingFunction> <local:RandomJitterEase EasingMode="EaseIn" Jitter="1000"></local:RandomJitterEase> </DoubleAnimation.EasingFunction> </DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Window.Triggers> <Canvas Margin="10"> <Ellipse Name="ellipse1" Canvas.Left="0" Fill="Red" Width="20" Height="20"></Ellipse> <Ellipse Name="ellipse2" Canvas.Top="100" Canvas.Left="0" Fill="Red" Width="20" Height="20"></Ellipse> </Canvas></Window>效果图如下所示,可以看到上面的圆圈平滑向右移动,下面的圆圈来回缓动向右移动:

(0)

相关推荐

  • WPF 动画实战 点击时显示圆圈淡出效果

    本文告诉大家一个有趣的动画,在鼠标点击的时候,在点击所在的点显示一个圆圈,然后这个圆圈做动画变大,但是颜色变淡的效果.本文的控件可以让大家将对应的容器放在自己应用里面就能实现这个效果 这个效果特别简单 ...

  • 【WPF学习】第四十九章 基本动画

    在前一章已经学习过WPF动画的第一条规则--每个动画依赖于一个依赖项属性.然而,还有另一个限制.为了实现属性的动态化(换句话说,使用基于时间的方式改变属性的值),需要有支持相应数据类型的动画类.例如, ...

  • WPF 添加提示动画

    下面放一张效果图: 那么具体是怎么实现呢: 前端XAML中: <Image Source="/Images/tips.png" HorizontalAlignment=&qu ...

  • [WPF 学习] 13.DataTrigger之EnterAction和ExitAction

    原来的需求是控件可见时有动画,不可见的时候没有动画,只写了EnterAction,没写ExitAction,以为空间都隐藏了,总不会再有动画了.刚好该动画在一个摄像头获取的视频上面,动画期间视频有点卡 ...

  • 学习道德经第十一章,请你举出4个因为“无”而产生作用的物品?

    学习<道德经>第十一章,请你举出四个因为"无'而产生作用的物品. 先来看看<道德经>第十一章的原文:三十辐共一毂,当其无,有车之用.埏埴以为器,当其无,有器之用.凿户 ...

  • 《道德经》五十一章《尊道贵德》悟读述杂【51】

    《道德经》五十一章《尊道贵德》悟读述杂【51】

  • 阴魂不散●第五十一章 石棺在哪里

    (朗读者:自洽) 欢迎关注佳丽世界,以方便<阴魂不散>小说阅读收听. 顾维之觉得无论如何,石棺现在成为一切谜团的关键.石棺在武圣庙出现,那么杀害齐明汉和魏必成.盗走银行款项以及所有恐吓就全 ...

  • 《女娲图的秘密》第五十一章:墨璃和紫菡的冲突

    女娲图的秘密 长篇奇幻小说 <女娲图的秘密> 即将出版 免费抢先看 连载中-- 第五十一章 墨璃和紫菡的冲突 第五十一章 "对了,接下来我们该何去何从?"沈宜林率先打破 ...

  • 《广州棋坛六十年》第一百五十一章 卢辉高徒李志海

    第一百五十一章 卢辉高徒李志海 四十年代后期的广州祥珍棋坛,出现了小将李志海,继曾益谦.邓球之后,夺得一九四七年广州象棋赛冠军. 李志海,广东新会人.十多岁时在广东省立第一职业学校读书,课余悉心习弈. ...

  • 《孙大圣之东海荡寇》第五十一章,严嵩倒台的连锁反应

    上回书说到,孙大圣随戚家军夜袭林墩,没想到遭遇埋伏,还面临一场惨烈的血战. 冲杀,到处都是血花四溅,对付倭寇没有什么好商量的,刀剑取命,唯有如此,才能不负戚家军威名.孙大圣和朱啸能被及时赶到的戚继光给 ...

  • 快穿之锦鲤系统姐就是拽 第五十一章

    文字丨宁柒 图丨北堂文学舍 快穿之锦鲤系统姐就是拽 宋浅晗的心事 51 "我--这不是给你介绍下我早年苦兮兮的经历吗?顺便介绍下我和师父的师徒情起端,再顺便介绍下让你躺了三年的苏棠.&quo ...

  • 《道德经》文言文新校注版第五十一章至第六十章

    开经语 宣道贵德抱无得一 行善利生济世救人 虚静恬淡寂寞无为 知强守柔神定气闲 求真返朴天地人和 慈心大用智慧超逸 道常无名玄同无碍 上德无己法雨无边 学习道德经,开启大智慧 第五十一章 [道德育儿篇 ...

  • 有而当其无,人生大智慧!道德经第五十一章

    第五十一章 道生之,而德畜之:物形之,而器成之: 是以万物遵道而贵德. 道之尊,德之贵也,夫莫之爵,而恒自然也. 道,生之畜之,长之遂之,亭之毒之,养之覆之. 生而弗有也,为而弗恃也,长而弗宰也,此之 ...