【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以及QuinticEase | Power属性用于设置公式中的指数。将该属性设置为2会复制QuadraticEase的效果,设置为3会复制CubicEase的效果。设置为4会复制QuarticEase的效果。设置为5会复制QuinticEase效果,或选择其他不同值,默认值是2 |
| ExponentialEase | 使用指数函数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, );
}
最后,下面是一个执行更有趣内容的自定义缓动函数——以一定的随机量便宜规范化的时间值,导致分散的抖动效果。可使用提供的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 == ) return ; // Offset the value by a random amount.
return Math.Abs(normalizedTime - (double)rand.Next(, ) / ( - 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(), new ValidateValueCallback(ValidateJitter)); private static bool ValidateJitter(object value)
{
int jitterValue = (int)value;
return ((jitterValue <= ) && (jitterValue >= ));
} // 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>
效果图如下所示,可以看到上面的圆圈平滑向右移动,下面的圆圈来回缓动向右移动:

【WPF学习】第五十一章 动画缓动的更多相关文章
- 【WPF学习】第二十一章 特殊容器
内容控件不仅包括基本控件,如标签.按钮以及工具提示:它们还包含特殊容器,这些容器可用于构造用户界面中比较大的部分区域. 首先介绍ScrollViewer控件,该控件直接继承自ContentContro ...
- “全栈2019”Java第五十一章:继承与final关键字详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- Gradle 1.12用户指南翻译——第五十一章. 发布构件
本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见:http://blog.csdn.net/column/details/gradle-translation.html翻译项目请关注Github上 ...
- 背水一战 Windows 10 (15) - 动画: 缓动动画
[源码下载] 背水一战 Windows 10 (15) - 动画: 缓动动画 作者:webabcd 介绍背水一战 Windows 10 之 动画 缓动动画 - easing 示例演示缓动(easing ...
- 重新想象 Windows 8 Store Apps (19) - 动画: 线性动画, 关键帧动画, 缓动动画
原文:重新想象 Windows 8 Store Apps (19) - 动画: 线性动画, 关键帧动画, 缓动动画 [源码下载] 重新想象 Windows 8 Store Apps (19) - 动画 ...
- 【WPF学习】第五十三章 动画类型回顾
创建动画面临的第一个挑战是为动画选择正确的属性.期望的结果(例如,在窗口中移动元素)与需要使用的属性(在这种情况下是Canvas.Left和Canvas.Top属性)之间的关系并不总是很直观.下面是一 ...
- o'Reill的SVG精髓(第二版)学习笔记——第十一章
第十一章:滤镜 11.1滤镜的工作原理 当SVG阅读器程序处理一个图形对象时,它会将对象呈现在位图输出设备上:在某一时刻,阅读器程序会把对象的描述信息转换为一组对应的像素,然后呈现在输出设备上.例如我 ...
- 过渡与动画 - 缓动效果&基于贝塞尔曲线的调速函数
难题 给过渡和动画加上缓动效果是一种常见的手法(比如具有回弹效果的过渡过程)是一种流行的表现手法,可以让界面显得更加生动和真实:在现实世界中,物体A点到B点往往也是不完全匀速的 以纯技术的角度来看,回 ...
- window.requestAnimationFrame与Tween.js配合使用实现动画缓动效果
window.requestAnimationFrame 概述 window.requestAnimationFrame()这个方法是用来在页面重绘之前,通知浏览器调用一个指定的函数,以满足开发者操作 ...
随机推荐
- jQuery篇
jQuery 1.为什么使用jQuery? js中window onload事件只能出现一次,如果出现多次,后面的事件会覆盖掉前面的事件 js代码容错差 简单的动画效果实现很繁琐,例如简单的动画渐变效 ...
- 【转】Linux虚拟终端命令Screen用法详解
转自 http://www.linuxidc.com/Linux/2013-07/87415.htm 在使用ssh或者telnet登录远程主机后,执行一些耗时的命令,如果此时ssh或者telnet中断 ...
- 51)PHP,一个数据库操作类的代码
<?php //类名,也习惯上(推荐)使用跟文件名相似的名字 //定义一个mysql连接类,该类可以连接mysql数据库 //并实现其单例模式 //该类的功能还能够完成如下基本mysql操作: ...
- python3多线程应用详解(第四卷:图解多线程中LOCK)
先来看下图形对比: 发现没有这种密集型计算的任务中,多线程没有穿行的速率快,原因就是多线程在线程切换间也是要耗时的而密集型计算任务执行时几乎没以偶IO阻塞,这样你说谁快
- 实战_3:新建产品配置(product)并导出项目
产品配置Product 产品配置用于定义和管理RCP应用的多个方面特征.并支持将RCP项目导出为部署包(类似eclipse压缩包),可以直接部署到其他环境上使用. 产品配置必须新建一个 扩展名为 .p ...
- BigDecimal不整除的一个异常java.lang.ArithmeticException
转载地址:http://blog.csdn.net/jobjava/article/details/6764623 金额的数据类型是BigDecimal 通过BigDecimal的divide方法进行 ...
- iOS仿写有妖气漫画、视频捕获框架、启动页广告页demo、多种动画效果等源码
iOS精选源码 以tableview的section为整体添加阴影效果/ta'b'le'vi'e'w顶部悬浮.... 一个可以轻松应用自定义过滤器的视频捕获框架. 基于UITableView的组件,旨 ...
- Linux SSH 使用密钥登陆
Linux SSH 使用密钥登陆 通常我们登录 Linux 服务器,我们需要使用密码进行登录,但是密码存在被暴力破解的可能. 可以将默认服务端口 22 改成其他不常用的端口. 可以设置非常复杂的密码. ...
- python3下scrapy爬虫(第五卷:初步抓取网页内容之scrapy全面应用)
现在爬取http://category.dangdang.com/pg1-cid4008149.html网址上的商品价格,名称,评价数量 先准备下下数据:商品名,商品链接,评价数量 第一步:在item ...
- CentOS 7上Docker的安装
一.安装docker 1.Docker 要求 CentOS 系统的内核版本高于 3.10 ,查看本页面的前提条件来验证你的CentOS 版本是否支持 Docker . 通过 uname -r 命令查看 ...