【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, 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>

效果图如下所示,可以看到上面的圆圈平滑向右移动,下面的圆圈来回缓动向右移动:

原文地址:https://www.cnblogs.com/Peter-Luo/p/12384509.html

时间: 2024-08-13 23:30:57

【WPF学习】第五十一章 动画缓动的相关文章

【WPF学习】第十一章 理解依赖项属性

依赖项属性是标准.NET属性的全新实现——具有大量新增价值.在WPF的核心特性(如动画.数据绑定以及样式)中需要嵌入依赖项属性.WPF元素提供的大多数属性都是依赖项属性.到目前位置所见到的所有示例都用到了依赖项属性,但你可能还没有意识到这一点.这是因为依赖项属性的用法和普通属性的是相同的. 然而,依赖项属性并非普通属性.可能乐意认为依赖项属性是添加了一套WPF功能的常规属性(采用典型的.NET方式进行定义).从概念上讲,依赖项属性确实以这种方式工作,但它们的背后的实现方式并非如此.原因十分简单:

【WPF学习】第二十一章 特殊容器

内容控件不仅包括基本控件,如标签.按钮以及工具提示:它们还包含特殊容器,这些容器可用于构造用户界面中比较大的部分区域. 首先介绍ScrollViewer控件,该控件直接继承自ContentControl类,提供了虚拟界面,允许用户围绕更大的元素滚动.与所有内容控件一样,ScrollViewer只能包含单个元素,虽然如此,你仍可在内部放置布局容器来保存自己需要的任意类型的元素. 此后将分析附加继承层中的另外三个控件:GroupBox.TabItem以及Expander.所有这些控件都继承自Head

o&#39;Reill的SVG精髓(第二版)学习笔记——第十一章

第十一章:滤镜 11.1滤镜的工作原理 当SVG阅读器程序处理一个图形对象时,它会将对象呈现在位图输出设备上:在某一时刻,阅读器程序会把对象的描述信息转换为一组对应的像素,然后呈现在输出设备上.例如我们用SVG的<filter>元素指定一组操作(也称作基元,primitive),在对象的旁边显示一个模糊的投影,然后把这个滤镜附加给一个对象: <fliter id="drop-shadow"> <!-- 这是滤镜操作 --> </fliter&g

Java学习笔记—第十一章 多线程机制

第十一章 Java多线程机制 了解Java中的进程与线程 1.1 进程:一般程序的结构大致可分为一个入口.一个出口和一个顺序执行的语句序列.程序运行时,系统从程序入口开始,按照语句的执行顺序(包括顺序.分支和循环)完成相应指令,然后从出口退出,程序结束.这样的结构称为进程.可以说,进程就是程序的一次动态执行的过程.一个进程既包括程序的代码,同时也包括系统的资源,如CPU.内存空间等.不同的进程所占用的系统资源都是独立的. 1.2 线程:线程是比进程更小的执行单位.一个进程在执行过程中,为了同时完

Android学习笔记—第十一章 Fragment

第十一章 Fragment android-supportV4: Android在新版本新增功能的兼容包,最低兼容1.6 路径:adt-bundle-windows-x86-20131030\sdk\extras\android\support\v4 功能:Fragment.ViewPager.视频播放 查看supportV4源代码: (1)在项目lib文件夹上new→file,文件名为android-support-v4.jar.properties (2)编辑文件内容: src=xxx:\\

window.requestAnimationFrame与Tween.js配合使用实现动画缓动效果

window.requestAnimationFrame 概述 window.requestAnimationFrame()这个方法是用来在页面重绘之前,通知浏览器调用一个指定的函数,以满足开发者操作动画的需求.这个方法接受一个函数为参,该函数会在重绘前调用. 注意: 如果想得到连贯的逐帧动画,函数中必须重新调用 requestAnimationFrame(). 如果你想做逐帧动画的时候,你应该用这个方法.这就要求你的动画函数执行会先于浏览器重绘动作.通常来说,被调用的频率是每秒60次,但是一般

动画: 缓动动画

演示缓动(easing)的应用Animation/EasingAnimation.xaml <Page x:Class="Windows10.Animation.EasingAnimation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xml

【WPF学习】第十三章 理解路由事件

每个.NET开发人员都熟悉“事件”的思想——当有意义的事情发生时,由对象(如WPF元素)发送的用于通知代码的消息.WPF通过事件路由(event routing)的概念增强了.NET事件模型.事件路由允许源自某个元素的事件由另一个元素引发.例如,使用事件路由,来自工具栏按钮的单击事件可在被代码处理之前上传到工具栏,然后上传到包含工具栏的窗口. 事件路由为在最合适的位置编写紧凑的.组织良好的用于处理事件的代码提供了灵活性.要使用WPF内容模型,事件路由也是必需的,内容模型允许使用许多不同的元素构建

学习笔记 第十一章 CSS3布局基础

第11章   CSS3布局基础 [学习重点] 了解CSS2盒模型. 设计边框样式. 设计边界样式. 设计补白样式. 了解CSS3盒模型. 11.1  CSS盒模型基础 页面中所有元素基本显示形态为方形的盒子(Box),根据盒模型规则,网页中所有元素对象都被放在一个盒子里,设计师可以通过CSS来控制这个盒子的显示方式. 11.1.1 盒模型结构 Box具有如下特点: 每个盒子都有:边界.边框.填充.内容4个属性. 每个属性都包括4个部分:上.右.下.左.属性的四部分可以同时设置,也可以分别设置.