zoukankan      html  css  js  c++  java
  • WPF中的动画——(二)From/To/By 动画

    我们所实现的的动画中,很大一部分是让一个属性在起始值和结束值之间变化,例如,我在前文中实现的改变宽度的动画:

        var widthAnimation = new DoubleAnimation()
        {
            From = 0,
            To = 320,
            Duration = TimeSpan.FromSeconds(2),
            RepeatBehavior = RepeatBehavior.Forever,
        };

        button.BeginAnimation(WidthProperty, widthAnimation);

    这个动画实现了宽度在0和320之间的变化,由于宽度是一个double型,因此这里用的是DoubleAnimation。对于一些其它常见的类型,如Byte、Color、Int32、Size、Point等,在System.Windows.Media.Animation下都有相应的过渡动画实现,命名规则是"数据结构类型+Animation"这里就不多介绍了。

    这种过渡动画一般成为From/To/By 动画,是因为它们是通过From、To、By三个属性来决定了目标属性的起始值和结束值。首先我们来看下这三个属性代表的意义:

    • From: 起始值,在动画开始的时候将目标属性设置为该值
    • To: 结束值,动画结束是目标属性为改值
    • By: 偏移值:动画结束的时候目标属性为"初始值+偏移值"

    很明显,To和By的效果是有可能冲突的。实际上,这三个属性都是可选设置的,并且在设置了To和By的时候,是会忽略By属性的。下面我再通过一些简单的场景介绍一下这三个属性如何组合使用。

    • 由0 变为 320:        From = 0, To = 320
    • 由初始值变为320:   To = 320
    • 由0变为初始值:       From = 0
    • 由0增大150:          From = 0, By = 150
    • 由初始值增大150:   By = 150

    看了这几个用例后,相信大家已经大致能明白这三个参数的使用方法。

    为什么这么设计

    初一看上去,这种From、To、By的三参数设计得过于复杂,完全可以用From和To两个参数可以确定,需要用到By的地方通过运算获取。 甚至From和To也可以强制要求赋值,这样就不会出现From和To都不赋值的这种非法情况了。为什么要这么设计呢? 我觉得有两个原因:

    1. 这种比较灵活的方式可以方便将动画和具体的对象分离出来,可以方便复用和组合。
    2. 方便在XAML中使用。如果像我上述的那样的做法,很多时候需要取对象的初始值,用XAML编写复杂的动画时,这种操作并不是是很方便。

    时间控制

    这里只介绍了如何设置过渡动画的起始状态和终止状态,动画还有一个比较重要部分是时间控制,如动画时间段的长度、开始时间、重复次数、进度的快慢,结束通知等。这些都是在其基类TimeLine中控制的,下一章将单独对其介绍。

    缓动函数可以通过一系列公式模拟一些物理效果,如实地弹跳或其行为如同在弹簧上一样。它们一般应用在From/To/By动画上,可以使得其动画更加平滑。

        var widthAnimation = new DoubleAnimation()
        {
            From = 0,
            To = 320,
            Duration = TimeSpan.FromSeconds(1),
            EasingFunction = new BackEase()
            {
                Amplitude = 0.3,
                EasingMode = EasingMode.EaseOut,
            },
        };

        button.BeginAnimation(WidthProperty, widthAnimation);

    从上面的例子可以看出,可以通过设置EasingFunction属性来使能缓动函数,通过 EasingMode 控制缓动函数的行为方式,它是一个枚举,有如下三个选项:

    • EaseIn :动画起始部分使能缓动函数
    • EaseOut :动画结束部分使能缓动函数
    • EaseInOut :动画起始和结束部分都使能缓动函数

    内置的缓动函数:

    系统内部内置了一系列缓动函数,可以参考下图选择所需要的函数。

     

    与 From/To/By 动画类似,关键帧动画以也可以以动画形式显示目标属性值。 和From/To/By 动画不同的是, From/To/By 动画只能控制在两个状态之间变化,而关键帧动画则可以在多个状态之间变化,例如,对于前面那个改变按钮宽度的例子,如果我们要实现如下效果:

    • 在2秒时将宽度从 0变为350
    • 在7秒时将宽度变为50
    • 在9秒的时候将其宽度变为200

    虽然我们可以用三个From/To/By 动画组合实现类似效果,但是这样一来麻烦,二来要感知动画完成事件,不方便在XAML中使用。此时我们则可以使用关键帧动画来快速实现这一过程。

        var widthAnimation = new DoubleAnimationUsingKeyFrames();
        var keyFrames = widthAnimation.KeyFrames;

        keyFrames.Add(new LinearDoubleKeyFrame(0, TimeSpan.FromSeconds(0)));
        keyFrames.Add(new LinearDoubleKeyFrame(350, TimeSpan.FromSeconds(2)));
        keyFrames.Add(new LinearDoubleKeyFrame(50, TimeSpan.FromSeconds(7)));
        keyFrames.Add(new LinearDoubleKeyFrame(200, TimeSpan.FromSeconds(9)));

        button.BeginAnimation(WidthProperty, widthAnimation);

    可以看出,关键帧动画将每一个状态制定为一个关键帧,关键帧动画时间线自动连接各个关键帧,并计算过渡状态,完成动画。因此,某种程度上,我们也可以把From/To/By 动画看成是只有两个状态的特殊关键帧动画。

    内置的关键帧动画

    与 From/To/By 动画一样,在名字空间System.Windows.Media.Animation 下也内置了大量关键帧动画,它们的命名规则是:    

        <类型> AnimationUsingKeyFrames

    例如这儿使用的DoubleAnimationUsingKeyFrames,其它类型请参看MSDN:关键帧动画概述,这里就不列举了。

    插值算法

    在关键帧动画中,我们除了定义关键帧外,还需要定义两个关键帧之间的插值算法,这样系统才能根据关键帧和插值算法生成中间状态。WPF系统内置四种插值算法:

    • 线性:    两个关键帧之间均匀变化
    • 离散:    两个关键帧之间突变(到达时间点的时候硬切换,没有过渡效果)
    • 样条:    使用贝塞尔曲线实现更精确的加速和减速控制
    • 缓动:    使用缓动函数曲线实现弹性变化

    综上来看,线性算法最常用,样条算法能实现精准加速和减速控制。离散的这种硬切换的效果虽然看起来没有什么动画效果,但用于连接关键帧还是比较常用的。另外在一些硬过渡的地方也是能用到的,例如实现闪烁效果。

    这几种算法的具体效果这里就不做更多的介绍了,感兴趣的朋友可以看看如下两个链接中的描述和例子:

    值得一提的是,并不是所有关键帧动画都支持这几种算法的,具体支持情况请参看MSDN:关键帧动画概述。 当然,对于不支持的也是可以自己手动实现的。

    关键帧(IKeyFrame)

    前面已经介绍过,一个关键帧主要有时间点和插值算法两部分组成,在WPF中,不同的关键帧动画对应着同的关键帧对象,它们都继承自IKeyFrame接口,其命名规则为:

        <类型> KeyFrame

    例如,DoubleAnimationUsingKeyFrames对应的是DoubleKeyFrame,但由于这个类并没有制定插值算法,它只是一个抽象基类,再加上插值算法后对应的关键帧类命名规范为:

        <插值算法><类型> KeyFrame

    例如,DoubleKeyFrame对应的几种插值算法的关键帧为:LinearDoubleKeyFrame、DiscreteDoubleKeyFrame、SplineDoubleKeyFrame、EasingDoubleKeyFrame。这些关键帧对象使用的方式都比较类似,这里就不多介绍了。

    关键帧的时间点(KeyTime)

    关键帧的时间点由IKeyFrame.KeyTime属性指定。它是一个KeyTime类型,它有如下几种取值类型:

    • 时间点TimeSpan: 靠TimeSpan直接决定时间点,可以通过函数KeyTime.FromTimeSpan()创建,也可以直接用TimeSpan隐式转换。
    • 相对时间Percent:  指定的是百分比,通过时间线的Duration来联合决定对应的时间点。通过函数KeyTime.FromPercent()创建。
    • 特殊值Uniform:    时间线平均分布每个关键帧所需要的时间。通过函数KeyTime.Uniform创建。
    • 特殊值Paced:      间线按固定的帧率分配所需时间,这种情况下,变化大的关键帧分配时间长,变化小的关键帧分配时间段。通过函数KeyTime.Paced创建。

    用代码创建的方式这儿就不举例了,这里就仅仅列举一下如何在XAML中表示这几种时间:

        <LinearDoubleKeyFrame Value="100" KeyTime="0:0:3" />
        <LinearDoubleKeyFrame Value="100" KeyTime="30%" />
        <LinearDoubleKeyFrame Value="100" KeyTime="Uniform" />
        <LinearDoubleKeyFrame Value="100" KeyTime="Paced" />

     
     
     
  • 相关阅读:
    Swift之 ? 和 !
    objective-c工程使用swift
    NSMethodSignature和NSInvocation的用法
    NSTimer
    iOS 的 XMPPFramework
    计算string高度
    python学习:猜数字小游戏
    python 各种控制语句
    ③ 小程序的代码组成
    ③ 组件&props
  • 原文地址:https://www.cnblogs.com/bruce1992/p/14742996.html
Copyright © 2011-2022 走看看