• WPF关键帧动画


    点击观看视频教程

    本章介绍关键帧动画之前, 首先需要讲解一下关于WPF当中基础动画与本章所讲的关键帧动画的区别。

    动画与关键帧的区别

    普通动画

    WPF基础动画当中, 我们熟悉的Form/To/By驱动的动画, 主要在两个值之间创建过渡效果, 如下图所示:

    关键帧

    对于关键帧动画而言,关键帧动画没有Form/To/By的属性, 而关键帧动画的值则是使用帧对象来进行描述, 故称之为关键帧动画, 如下所示:

    注: 关键帧对象(Frame) 主要包含两个参数, Value是目标值, KeyTime 则表达的是时间

    介绍关键帧动画

    下面,介绍了如何创建一个简单的关键帧动画。
    1.如下代码,创建了一个矩形, 为其添加了一个点击时间触发动画, 该动画在Storyboard中定义并且触发:

    <Border Width="400" BorderBrush="Black">  
        <Rectangle Fill="Blue" 
          Width="50" Height="50"
          HorizontalAlignment="Left">
          <Rectangle.RenderTransform>
            <TranslateTransform 
              x:Name="MyAnimatedTranslateTransform" 
              X="0" Y="0" />
          </Rectangle.RenderTransform>
          <Rectangle.Triggers>
            <EventTrigger RoutedEvent="Rectangle.MouseLeftButtonDown">
              <BeginStoryboard>
                <Storyboard>
                  <DoubleAnimationUsingKeyFrames
                    Storyboard.TargetName="MyAnimatedTranslateTransform"
                    Storyboard.TargetProperty="X"
                    Duration="0:0:10">
                    <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0" />
                    <LinearDoubleKeyFrame Value="350" KeyTime="0:0:2" />
                    <LinearDoubleKeyFrame Value="50" KeyTime="0:0:7" />
                    <LinearDoubleKeyFrame Value="200" KeyTime="0:0:8" />                          
                  </DoubleAnimationUsingKeyFrames>
                </Storyboard>
              </BeginStoryboard>
            </EventTrigger>
          </Rectangle.Triggers> 
        </Rectangle>
      </Border> 
    

    说明:以上的创建了一个DoubleAnimation类型的帧动画, 为其绑定了一个目标及目标的动画依赖属性 "Y", Duration则为其设定了一个帧动画持续时间,在关键帧动画的集合中, 定义了多个线性关键帧(LinearDoubleKeyFrame), 为其设定了Value目标值和KeyTime持续时间。

    此处说讲到的线性关键帧所属其中的一种类型, 在后面将会有更多的介绍。

    关键帧动画类型

    关键帧动画属于System.Windows.Media.Animation命令空间下, 命名规则约定为

    关键帧的动画类型列表

    帧对象的类型

    正如我们创建不同类型的动画, 我们需要按照约定命名方式定义, 如: DoubleAnimation, ColorAnimation 等等。
    对于帧动画而言, 主要由一个或者N个帧对象组成(Frame), 帧对象同时也拥有不同的种类, 故帧对象遵循一下的命名约定:
    <插值方法><类型>

    关键帧的主要目的是指定 和KeyTime、Value 每个关键帧类型都可提供这两种属性。

    • 属性Value指定该关键帧的目标值。
    • 该KeyTime属性指定何时(在动画的Duration)中到达关键帧。 Value
      当关键帧动画开始时,按其KeyTime属性定义的顺序遍接其关键帧。
    • 如果时间 0 时没有关键帧,动画会在目标属性的当前值和第Value一个关键帧之间的转换;否则,动画的输出值将成为第一个关键帧的值。
    • 动画使用第二个关键帧指定的Value插值方法在第一个关键帧和第二个关键帧之间创建过渡。 转换从第一个关键帧开始KeyTime,并在到达第二个关键帧KeyTime时结束。
    • 动画将继续,这会创建每个后续关键帧和其前面的关键帧之间的过渡。
    • 最后,动画转换为关键帧的值,其最大键时间等于或小于动画的值Duration。
      如果动画的Duration或Automatic其Duration等于最后一个关键帧的时间,则动画结束。 否则,如果动画大于Duration最后一个关键帧的键时间,则动画将保留关键帧值,直到到达其Duration的末尾。 与所有动画一样,关键帧动画使用其FillBehavior属性来确定在到达活动周期结束时是否保留最终值。

    插值方法

    下面将主要介绍有三种不同类型的内插方法: 线性、离散和曲线。

    线性内插

    使用线性内插,动画将以段持续时间的固定速度进行播放。 例如,如果关键帧段从 0 过渡到 10,持续时间为 5 秒,则动画会在指定时间输出以下值:

    离散内插

    使用离散内插,动画函数将从一个值跳到下一个值,没有内插。 如果关键帧段从 0 过渡到 10,持续时间为 5 秒,则动画会在指定时间输出以下值:

    注: 通过观察线性和离散的插入比较, 可以清晰的看出来, 离线类型的插入方式, 在动画的执行过程中, 我们无法在规定的时间内观察其变化效果, 直接至时间结束后, 到指定的目标值。

    曲线内插

    曲线内插可能很难理解;使用不同的设置进行体验有助于理解。 通过主曲线动画示例,可以更改主曲线值,并查看由此所产生的动画结果, 可以查看最上方视频进行理解。

    组合内插

    可在一个关键帧动画中使用具有不同内插类型的关键帧。 如果两个具有不同内插的关键帧动画彼此跟随,第二个关键帧的内插方法将用于创建从第一个值到第二个值的过渡。
    下面的示例,演示了一个使用DoubleAnimationUsingKeyFrames创建使用线性、拼接和离散插值的示例:

          <Rectangle 
      Width="50"
      Height="50"
      Fill="Orange">  
      <Rectangle.RenderTransform>
        <TranslateTransform 
          x:Name="ComboAnimatedTranslateTransform" 
          X="0" Y="0" />
      </Rectangle.RenderTransform>
      <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Rectangle.Loaded">
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimationUsingKeyFrames
                Storyboard.TargetName="ComboAnimatedTranslateTransform"
                Storyboard.TargetProperty="X"
                Duration="0:0:15"
                RepeatBehavior="Forever">
                <DiscreteDoubleKeyFrame Value="500" KeyTime="0:0:7" />
                <LinearDoubleKeyFrame Value="200" KeyTime="0:0:10" />
                <SplineDoubleKeyFrame Value="350" KeyTime="0:0:15"  
                  KeySpline="0.25,0.5 0.75,1" />                      
              </DoubleAnimationUsingKeyFrames>           
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </Rectangle.Triggers> 
    </Rectangle>
    

    Duration与KeyTime

    与其他动画一样,关键帧动画具有属性Duration。 除了指定动画的Duration外,还需要指定每个关键帧的持续时间的哪一部分。 为此,您可以为每个动画的关键KeyTime帧描述 。 每个关键帧指定KeyTime该关键帧的结束时间。
    属性KeyTime不指定密钥时间播放的时间。 关键帧的播放时长由关键帧的结束时间、前一个关键帧的结束时间以及动画的持续时间确定。 关键时间可以指定为时间值、百分比或特殊值Uniform或Paced。

    TimeSpan

    以下示例演示一个持续时间为 10 秒钟、有四个关键帧(这些关键帧的关键时间指定为时间值)的动画。

    • 在前 3 秒钟内,第一个关键帧在基值和 100 之间进行动画处理,结束时间 = 0:0:03。
    • 第二个关键帧在 100 和 200 之间进行动画处理。 它在第一个关键帧结束后开始(开始时间 = 3 秒),播放 5 秒钟,结束时间 = 0:0:8。
    • 第三个关键帧在 200 和 500 之间进行动画处理。 它在第二个关键帧结束时开始(开始时间 = 8 秒),播放 1 秒钟,结束时间 = 0:0:9。
    • 第四个关键帧在 500 和 600 之间进行动画处理。 它在第三个关键帧结束时开始(开始时间 = 9 秒),播放 1 秒钟,结束时间 = 0:0:10。
          <Rectangle Width="50" Height="50" Fill="Blue">
      <Rectangle.RenderTransform>
        <TranslateTransform x:Name="TranslateTransform01" X="10" Y="30" />
      </Rectangle.RenderTransform>
      <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Rectangle.Loaded">
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimationUsingKeyFrames 
                Storyboard.TargetName="TranslateTransform01" 
                Storyboard.TargetProperty="X"
                Duration="0:0:10"
                RepeatBehavior="Forever">
    
                <!-- KeyTime properties are expressed as TimeSpan values 
                     which are in the form of "hours:minutes:seconds". -->
                <LinearDoubleKeyFrame Value="100" KeyTime="0:0:3" />
                <LinearDoubleKeyFrame Value="200" KeyTime="0:0:8" />
                <LinearDoubleKeyFrame Value="500" KeyTime="0:0:9" />
                <LinearDoubleKeyFrame Value="600" KeyTime="0:0:10" />
              </DoubleAnimationUsingKeyFrames>
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </Rectangle.Triggers>
    </Rectangle>
    

    百分比

    百分比值指定关键帧以动画的某些Duration百分比结束。 在 XAML 中,指定百分比作为 % 符号后的数字。 在代码中,使用FromPercent方法并传递一个Double指示百分比的方法。 该值必须大于或等于 0 并且小于或等于 100%。 以下示例演示一个持续时间为 10 秒钟、有四个关键帧(这些关键帧的关键时间指定为百分比)的动画。

    • 在前 3 秒钟内,第一个关键帧将在基值和 100 之间进行动画处理,结束时间 = 0:0:3。
    • 第二个关键帧在 100 和 200 之间进行动画处理。 它在第一个关键帧结束后开始(开始时间 = 3 秒),播放 5 秒钟,结束时间 = 0:0:8 (0.8 * 10 = 8)。
    • 第三个关键帧在 200 和 500 之间进行动画处理。 它在第二个关键帧结束时开始(开始时间 = 8 秒),播放 1 秒钟,结束时间 = 0:0:9 (0.9 * 10 = 9)。
    • 第四个关键帧在 500 和 600 之间进行动画处理。 它在第三个关键帧结束时开始(开始时间 = 9 秒),播放 1 秒钟,结束时间 = 0:0:10 (1 * 10 = 10)。
          <Rectangle Height="50" Width="50" Fill="Purple">
      <Rectangle.RenderTransform>
        <TranslateTransform x:Name="TranslateTransform02" X="10" Y="110" />
      </Rectangle.RenderTransform>
      <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Rectangle.Loaded">
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimationUsingKeyFrames 
                Storyboard.TargetName="TranslateTransform02" 
                Storyboard.TargetProperty="X"
                Duration="0:0:10"
                RepeatBehavior="Forever">
    
                <!-- KeyTime properties are expressed as Percentages. -->
                <LinearDoubleKeyFrame Value="100" KeyTime="30%" />
                <LinearDoubleKeyFrame Value="200" KeyTime="80%" />
                <LinearDoubleKeyFrame Value="500" KeyTime="90%" />
                <LinearDoubleKeyFrame Value="600" KeyTime="100%" />
              </DoubleAnimationUsingKeyFrames>
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </Rectangle.Triggers>
    </Rectangle>
    

    Uniform

    当您Uniform希望每个关键帧花费相同的时间时,请使用计时。
    Uniform关键时间将可用时间平均除以关键帧数,以确定每个关键帧的结束时间。 下面的示例显示持续时间为 10 秒的动画和四个关键帧,其关键时间指定为Uniform。

    • 在前 2.5 秒钟内,第一个关键帧在基值和 100 之间进行动画处理,结束时间 = 0:0:2.5。
    • 第二个关键帧在 100 和 200 之间进行动画处理。 它在第一个关键帧结束后开始(开始时间 = 2.5 秒),播放大约 2.5 秒钟,结束时间 = 0:0:5。
    • 第三个关键帧在 200 和 500 之间进行动画处理。 它在第二个关键帧结束时开始(开始时间 = 5 秒),播放 2.5 秒钟,结束时间 = 0:0:7.5。
    • 第四个关键帧在 500 和 600 之间进行动画处理。 它在第二个关键帧结束时开始(开始时间 = 7.5 秒),播放 2.5 秒钟,结束时间 = 0:0:1。
          <Rectangle Height="50" Width="50" Fill="Red">
      <Rectangle.RenderTransform>
        <TranslateTransform x:Name="TranslateTransform03" X="10" Y="190" />
      </Rectangle.RenderTransform>
      <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Rectangle.Loaded">
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimationUsingKeyFrames 
                Storyboard.TargetName="TranslateTransform03" 
                Storyboard.TargetProperty="X"
                Duration="0:0:10"
                RepeatBehavior="Forever">
    
                <!-- KeyTime properties are expressed with values of Uniform. 
                     When a key time is set to "Uniform" the total allotted 
                     time of the animation is divided evenly between key frames.  
                     In this example, the total duration of the animation is 
                     ten seconds and there are four key frames each of which 
                     are set to "Uniform", therefore, the duration of each key frame 
                     is 3.3 seconds (10/3). -->
                <LinearDoubleKeyFrame Value="100" KeyTime="Uniform" />
                <LinearDoubleKeyFrame Value="200" KeyTime="Uniform" />
                <LinearDoubleKeyFrame Value="500" KeyTime="Uniform" />
                <LinearDoubleKeyFrame Value="600" KeyTime="Uniform" />
              </DoubleAnimationUsingKeyFrames>
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </Rectangle.Triggers>
    </Rectangle>
    

    Paced

    如果要Paced以恒定速率进行动画处理,请使用计时。
    Paced关键时间根据每个关键帧的长度分配可用时间,以确定每个帧的持续时间。 这样,动画的速度或速率将保持不变。 下面的示例显示持续时间为 10 秒的动画和三个关键帧,其关键时间指定为Paced。

          <Rectangle Height="50" Width="50" Fill="Orange">
      <Rectangle.RenderTransform>
        <TranslateTransform x:Name="TranslateTransform04" X="10" Y="270" />
      </Rectangle.RenderTransform>
      <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Rectangle.Loaded">
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimationUsingKeyFrames 
                Storyboard.TargetName="TranslateTransform04" 
                Storyboard.TargetProperty="X"
                Duration="0:0:10"
                RepeatBehavior="Forever">
    
                <!-- KeyTime properties are expressed with values of Paced. 
                     Paced values are used when a constant rate is desired. 
                     The time allocated to a key frame with a KeyTime of "Paced" 
                     is determined by the time allocated to the other key 
                     frames of the animation. This time is calculated to 
                     attempt to give a "paced" or "constant velocity" 
                     for the animation. -->
                <LinearDoubleKeyFrame Value="100" KeyTime="Paced" />
                <LinearDoubleKeyFrame Value="200" KeyTime="Paced" />
                <LinearDoubleKeyFrame Value="500" KeyTime="Paced" />
                <LinearDoubleKeyFrame Value="600" KeyTime="Paced" />
              </DoubleAnimationUsingKeyFrames>
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </Rectangle.Triggers>
    </Rectangle>
    

    关键帧时间及顺序

    可以在同一动画中使用具有不同KeyTime值类型的关键帧。 尽管建议以关键帧的实际播放顺序来添加关键帧,但此操作不是必需的。 动画和计时系统能够处理顺序紊乱的关键帧。 将忽略关键时间无效的关键帧。
    下表描述了为关键帧动画的关键帧解析关键时间的过程。
    1 解析TimeSpanKeyTime值。
    2 确定动画的总内插时间,即关键帧动画完成向前迭代所需的全部时间。
    如果动画的Duration不是Automatic或Forever,则总插值时间是动画Duration属性的值。
    否则,总插值时间是其关键帧(TimeSpanKeyTime如果有)之间指定的最大值。
    否则,总内插时间为 1 秒。
    3 使用总插值时间值解析PercentKeyTime值。
    4 如果最后一个关键帧尚未在之前步骤中解析,则将解析该关键帧。 如果最后KeyTime一个关键帧为Uniform或Paced,则其解析时间将等于总插值时间。
    如果第KeyTime一个关键帧的,Paced并且此动画比关键帧多,则将其KeyTime值解析为零;如果只有一个关键帧,并且其KeyTime值为Paced,则解析为总插值时间,如上一步所述。
    5 解析剩余UniformKeyTime值:每个值都给定可用时间的相等份额。 在此过程中PacedKeyTime,未解析的值将暂时视为UniformKeyTime值,并获得临时解析的时间。
    6 使用声明KeyTime的最接近具有已解析KeyTime值的关键帧,解决未指定密钥时间的关键帧的值。
    7 解析剩余PacedKeyTime值。 PacedKeyTime使用相邻KeyTime关键帧的值来确定其解析时间。 目的是确保动画速度在此关键帧的解析时间内保持固定不变。
    8 按解析时间(主键)和声明顺序(辅助键)对关键帧进行排序,即根据已解决的关键帧KeyTime值使用稳定排序。

  • 相关阅读:
    WebForm中使用MVC
    CPAN镜像使用帮助
    关于XML文档的xmlns、xmlns:xsi和xsi:schemaLocation
    XML之命名空间的作用(xmlns)
    xml相关术语说明
    .NET Core系列 : 1、.NET Core 环境搭建和命令行CLI入门
    BZOJ3734 : [Ontak2013]Miny
    BZOJ3448 : [Usaco2014 Feb]Auto-complete
    BZOJ3476 : [Usaco2014 Mar]The Lazy Cow
    BZOJ3619 : [Zjoi2014]璀灿光华
  • 原文地址:https://www.cnblogs.com/zh7791/p/12897696.html
Copyright © 2020-2023  润新知