Поделиться через


Анимации с ключевыми кадрами и анимации с функцией сглаживания

Линейные анимации ключевых кадров, анимации ключевых кадров с значением KeySpline или функции упрощения — это три различных метода примерно для одного сценария: создание раскадровной анимации, которая немного сложнее, и которая использует нелинейное поведение анимации от начального состояния до конечного состояния.

Предпосылки

Убедитесь, что вы прочитали раздел об анимированных раскадровках. Этот раздел основан на концепциях анимации, которые были описаны в анимации с использованием раскадровки и не рассматриваются снова. Например, раскадровка анимации описывает, как нацеливать анимацию, раскадровки как ресурсы, значения свойств временной шкалы , такие как Duration, FillBehavior и т. д.

Анимация с использованием ключевых кадров

Анимации с ключевым кадром позволяют достичь нескольких целевых значений, которые достигаются в точке вдоль временной шкалы анимации. Другими словами, каждый ключевой кадр может задавать своё промежуточное значение, и последний ключевой кадр определяет конечное значение анимации. Указав несколько значений для анимации, можно сделать более сложные анимации. Анимации с ключевым кадром также позволяют реализовать различные логики интерполяции, которые реализуются в качестве отдельного подкласса keyFrame для каждого типа анимации. В частности, каждый тип анимации с ключевым кадром имеет дискретный, линейный, spline и упрощенный вариант класса keyFrame для указания ключевых кадров. Например, чтобы указать анимацию, для которой целевым является Double и используется ключевые кадры, можно объявить ключевые кадры с Дискретными ключевыми кадрами DoubleKeyFrame, Линейными DoubleKeyFrame, Сплайнными DoubleKeyFrame, и Смягченными DoubleKeyFrame. Вы можете использовать любые и все эти типы в одной коллекции ключевых кадров , чтобы изменить интерполяцию при каждом достижении нового ключевого кадра.

Для поведения интерполяции каждый ключевой кадр управляет интерполяцией до достижения времени KeyTime . Его значение также достигается в это время. Если есть больше ключевых кадров дальше по ходу, это значение становится начальным для следующего ключевого кадра в последовательности.

В начале анимации, если ключевой кадр с KeyTime "0:0:0" отсутствует, начальное значение будет равно неанимированному значению свойства. Это похоже на то, как анимация от/до/By действует, если нет от.

Длительность анимации ключевого кадра неявно равна максимальному значению KeyTime , заданному в любом из ключевых кадров. Вы можете задать явную длительность, если хотите, но будьте осторожны: она не должна быть короче КлючевоеВремя в ваших собственных ключевых кадрах, иначе часть анимации будет отрезана.

Помимо длительности, вы можете задать все свойства, основанные на временной шкале, для анимации по ключевым кадрам, так же как и для анимации From/To/By, поскольку классы анимации по ключевым кадрам также являются производными от временной шкалы. К ним относятся:

  • AutoReverse: после достижения последнего ключевого кадра кадры повторяются в обратном порядке с конца. Это удвоит воспринятую длительность анимации.
  • BeginTime: задержка начала анимации. Временная шкала значений KeyTime в кадрах не начинает подсчет до тех пор, пока BeginTime не будет достигнута, поэтому нет риска отрезать кадры
  • FillBehavior: управляет тем, что происходит при достижении последнего ключевого кадра. FillBehavior не влияет на любые промежуточные ключевые кадры.
  • RepeatBehavior:
    • Если задано значение Forever, то ключевые кадры и их временная шкала повторяют бесконечно.
    • Если установлено значение количества итераций, временная шкала повторяется указанное количество раз.
    • Если задано значение "Длительность", временная шкала повторяется до достижения этого времени. Это может усечь анимацию в середине последовательности ключевых кадров, если она не является целым множителем продолжительности временной шкалы.
  • SpeedRatio (часто не используется)

Линейные ключевые кадры

Линейные ключевые кадры приводят к простой линейной интерполяции значения до тех пор, пока не будет достигнуто KeyTime кадра. Это характеристика интерполяции наиболее похожа на более простые анимации От/К/По, описанные в разделе раскадровка анимаций.

Это руководство по использованию анимации ключевых кадров для масштабирования высоты рендера прямоугольника с помощью линейных ключевых кадров. В этом примере выполняется анимация, в которой высота прямоугольника увеличивается немного и линейно в течение первых 4 секунд, а затем быстро масштабируется в течение последней секунды, пока прямоугольник не будет двойной начальной высоты.

<StackPanel>
    <StackPanel.Resources>
        <Storyboard x:Name="myStoryboard">
            <DoubleAnimationUsingKeyFrames
              Storyboard.TargetName="myRectangle"
              Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
                <LinearDoubleKeyFrame Value="1" KeyTime="0:0:0"/>
                <LinearDoubleKeyFrame Value="1.2" KeyTime="0:0:4"/>
                <LinearDoubleKeyFrame Value="2" KeyTime="0:0:5"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </StackPanel.Resources>
</StackPanel>

Дискретные ключевые кадры

Дискретные ключевые кадры вообще не используют интерполяцию. При достижении KeyTime новое Value просто применяется. В зависимости от анимируемого свойства UI, это часто создает анимацию, которая кажется "прыгающей". Будьте уверены, что это эстетическое поведение, которое вы действительно хотите. Вы можете свести к минимуму очевидные скачки, увеличив число ключевых кадров, которые вы задаете, но если гладкая анимация является вашей целью, вам лучше использовать линейные или сплайн ключевые кадры.

Замечание

Дискретные ключевые кадры — единственный способ анимации значения, которое не относится к типу Double, Point или Color, с DiscreteObjectKeyFrame. Далее мы обсудим это в этом разделе.

Ключевые кадры spline

Кадр ключа spline создает переменный переход между значениями в соответствии со значением свойства KeySpline . Это свойство задает первые и второй контрольные точки кривой Bezier, описывающие ускорение анимации. В основном KeySpline определяет зависимость функции от времени, где граф этой функции во времени имеет форму указанной кривой Безье. Обычно значение KeySpline указывается в строке атрибута XAML с четырьмя двойными значениями, разделенными пробелами или запятыми. Эти значения являются парами "X,Y" для двух контрольных точек кривой Bezier. "X" — это время, а "Y" — это модификатор функции для значения. Каждое значение всегда должно быть от 0 до 1 включительно. Без изменения точки управления в KeySpline прямая линия от 000 до 1,1 является представлением функции с течением времени для линейной интерполяции. Точки управления изменяют форму этой кривой и таким образом поведение функции с течением времени для анимации сплайна. Это, вероятно, лучше всего представить это визуально в виде графика. Вы можете запустить пример визуализатора ключевых сплайнов Silverlight в браузере, чтобы показать, как точки управления изменяют кривую, и как выполняется пример анимации при использовании в качестве значения KeySpline.

В следующем примере показаны три разных ключевых кадра, примененных к анимации, причем последний из них — ключевая сплайн-анимация для значения Double (SplineDoubleKeyFrame). Обратите внимание на строку "0.6,0.0 0.9,0.00", примененную для KeySpline. Это создает кривую, в которой анимация, как представляется, выполняется медленно, но затем быстро достигает значения непосредственно до достижения KeyTime .

<Storyboard x:Name="myStoryboard">
    <!-- Animate the TranslateTransform's X property
        from 0 to 350, then 50,
        then 200 over 10 seconds. -->
    <DoubleAnimationUsingKeyFrames
        Storyboard.TargetName="MyAnimatedTranslateTransform"
        Storyboard.TargetProperty="X"
        Duration="0:0:10" EnableDependentAnimation="True">

        <!-- Using a LinearDoubleKeyFrame, the rectangle moves 
            steadily from its starting position to 500 over 
            the first 3 seconds.  -->
        <LinearDoubleKeyFrame Value="500" KeyTime="0:0:3"/>

        <!-- Using a DiscreteDoubleKeyFrame, the rectangle suddenly 
            appears at 400 after the fourth second of the animation. -->
        <DiscreteDoubleKeyFrame Value="400" KeyTime="0:0:4"/>

        <!-- Using a SplineDoubleKeyFrame, the rectangle moves 
            back to its starting point. The
            animation starts out slowly at first and then speeds up. 
            This KeyFrame ends after the 6th second. -->
        <SplineDoubleKeyFrame KeySpline="0.6,0.0 0.9,0.00" Value="0" KeyTime="0:0:6"/>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

Упрощение ключевых кадров

Ключевой кадр упрощения — это ключевой кадр, в котором применяется интерполяция, а функция с течением времени интерполяции управляется несколькими предварительно определенными математическими формулами. На самом деле с помощью ключевого кадра сплайна вы можете создать практически такой же результат, как и с некоторыми типами функций сглаживания. Однако есть функции сглаживания, такие как BackEase, которые нельзя воспроизвести с помощью сплайна.

Чтобы применить функцию упрощения к ключевому кадру, необходимо задать свойство EasingFunction в качестве элемента свойства в XAML для этого ключевого кадра. Для значения укажите элемент объекта для одного из типов функций упрощения.

В этом примере применяется CubicEase, а затем BounceEase в качестве последовательных ключевых кадров к DoubleAnimation, чтобы создать эффект отскока.

<Storyboard x:Name="myStoryboard">
    <DoubleAnimationUsingKeyFrames Duration="0:0:10"
        Storyboard.TargetProperty="Height"
        Storyboard.TargetName="myEllipse">

        <!-- This keyframe animates the ellipse up to the crest 
            where it slows down and stops. -->
        <EasingDoubleKeyFrame Value="-300" KeyTime="00:00:02">
            <EasingDoubleKeyFrame.EasingFunction>
                <CubicEase/>
            </EasingDoubleKeyFrame.EasingFunction>
        </EasingDoubleKeyFrame>

        <!-- This keyframe animates the ellipse back down and makes
            it bounce. -->
        <EasingDoubleKeyFrame Value="0" KeyTime="00:00:06">
            <EasingDoubleKeyFrame.EasingFunction>
                <BounceEase Bounces="5"/>
            </EasingDoubleKeyFrame.EasingFunction>
        </EasingDoubleKeyFrame>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

Это только один пример функции упрощения. Дополнительные сведения см. в следующем разделе.

Упрощение функций

Функции упрощения позволяют применять пользовательские математические формулы к анимациям. Математические операции часто полезны для создания анимаций, которые имитируют реальную физику в 2-D-системе координат. Например, может потребоваться, чтобы объект реалистично отскакивал или вёл себя, как будто он был на пружине. Вы можете использовать ключевые кадры или даже анимации From/To/By для приближения этих эффектов, но это потребует значительных усилий, и точность анимации будет ниже, чем при использовании математической формулы.

Функции упрощения можно применять к анимациям тремя способами:

Ниже приведен список функций упрощения.

  • BackEase: отводит движение анимации незначительно, прежде чем начинает анимироваться по указанному пути.
  • BounceEase: создает эффект отскока.
  • CircleEase: создает анимацию, которая ускоряет или уменьшается с помощью циклической функции.
  • CubeEase: создает анимацию, которая ускоряет или уменьшается с помощью формулы f(t) = t3.
  • ElasticEase: создает анимацию, которая напоминает колебание пружины вперед и назад, пока она не прекратит движение.
  • ЭкспоненциальнаяEase: создает анимацию, которая ускоряет или уменьшается с помощью экспоненциальной формулы.
  • PowerEase: создает анимацию, которая ускоряет или уменьшается с помощью формулы f(t) = tp, где p равно свойству Power .
  • QuadraticEase: создает анимацию, которая ускоряет или уменьшается с помощью формулы f(t) = t2.
  • QuarticEase: создает анимацию, которая ускоряет или уменьшается с помощью формулы f(t) = t4.
  • QuinticEase: создание анимации, которая ускоряет или уменьшается с помощью формулы f(t) = t5.
  • SineEase: создает анимацию, которая ускоряет или уменьшается с помощью синусовой формулы.

Некоторые функции упрощения имеют собственные свойства. Например, BounceEase имеет два свойства Bounces и Bounciness , которые изменяют поведение функции с течением времени этого конкретного bounceEase. Другие функции плавности, такие как CubicEase, не имеют других свойств, кроме свойства EasingMode, которым обладают все функции плавности, и всегда создают одно и то же поведение во времени.

Некоторые из этих функций плавности имеют некоторое перекрытие в зависимости от того, как вы задаете свойства для функций плавности, имеющих свойства. Например, QuadraticEase точно совпадает с PowerEase, где Power равно 2. И CircleEase в основном является экспоненциальным интерполированием по умолчанию.

Функция упрощения BackEase уникальна, так как она может изменить значение вне обычного диапазона, заданное параметром From/To или значениями ключевых кадров. Она запускает анимацию, изменяя значение в противоположном направлении от ожидаемого для нормального поведения From/To, затем возвращается к значению From или начальному значению и после этого запускает анимацию в обычном режиме.

В предыдущем примере мы показали, как объявить функцию упрощения для анимации ключевых кадров. Следующий пример применяет функцию упрощения к анимации from/To/By .

<StackPanel x:Name="LayoutRoot" Background="White">
    <StackPanel.Resources>
        <Storyboard x:Name="myStoryboard">
            <DoubleAnimation From="30" To="200" Duration="00:00:3" 
                Storyboard.TargetName="myRectangle" 
                Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
                <DoubleAnimation.EasingFunction>
                    <BounceEase Bounces="2" EasingMode="EaseOut" 
                                Bounciness="2"/>
                </DoubleAnimation.EasingFunction>
            </DoubleAnimation>
        </Storyboard>
    </StackPanel.Resources>
    <Rectangle x:Name="myRectangle" Fill="Blue" Width="200" Height="30"/>
</StackPanel>

Когда функция упрощения применяется к анимации from// ToBy, она изменяет характеристики функции с течением времени о том, как значение интерполяется между значениями from и To в течение длительности анимации. Без функции упрощения это будет линейная интерполяция.

Анимации дискретных значений объектов

Один из типов анимации заслуживает особого упоминания, потому что это единственный способ применения анимированного значения к свойствам, которые не относятся к типа Double, Point или Color. Это ключевая анимация ObjectAnimationUsingKeyFrames. Анимация с помощью значений объектов отличается, так как нет возможности интерполяции значений между кадрами. После достижения keyTime кадра анимированное значение немедленно устанавливается в значение, указанное в значении ключевого кадра. Так как интерполяция отсутствует, в коллекции ключевых кадров ObjectAnimationUsingKeyFrames используется только один ключевой кадр: DiscreteObjectKeyFrame.

ЗначениеDiscreteObjectKeyFrame часто задается с помощью синтаксиса элемента свойства, так как значение объекта, которое вы пытаетесь задать, часто не может быть выражено в виде строки для заполнения Value в синтаксисе атрибута. Если вы используете ссылку, например StaticResource, можно использовать синтаксис атрибутов.

Одно из мест, где вы увидите использование ObjectAnimationUsingKeyFrames в шаблонах по умолчанию, это когда свойство шаблона ссылается на ресурс Brush. Эти ресурсы являются объектами SolidColorBrush, а не просто значением Color, и они используют ресурсы, определенные как системные темы (ThemeDictionaries). Они могут быть назначены непосредственно значению типа Кисть, например TextBlock.Foreground и не нужно использовать непрямое назначение. Но поскольку SolidColorBrush не является Double, точкой или Color, вам придется использовать ObjectAnimationUsingKeyFrames, чтобы воспользоваться ресурсом.

<Style x:Key="TextButtonStyle" TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid Background="Transparent">
                    <TextBlock x:Name="Text"
                        Text="{TemplateBinding Content}"/>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="PointerOver">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationPointerOverForegroundThemeBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationPressedForegroundThemeBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
...
                       </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Можно также использовать ObjectAnimationUsingKeyFrames для анимации свойств, использующих значение перечисления. Ниже приведен еще один пример именованного стиля, который поставляется из шаблонов среды выполнения Windows по умолчанию. Обратите внимание, как оно задает свойство Видимости , которое принимает константу перечисления Видимости . В этом случае можно задать значение с помощью синтаксиса атрибутов. Для задания свойства со значением перечисления требуется только неквалифицированное имя константы, например "Свернутый".

<Style x:Key="BackButtonStyle" TargetType="Button">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="Button">
          <Grid x:Name="RootGrid">
            <VisualStateManager.VisualStateGroups>
              <VisualStateGroup x:Name="CommonStates">
              <VisualState x:Name="Normal"/>
...           <VisualState x:Name="Disabled">
                <Storyboard>
                  <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Visibility">
                    <DiscreteObjectKeyFrame Value="Collapsed" KeyTime="0"/>
                  </ObjectAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
            </VisualStateGroup>
...
          </VisualStateManager.VisualStateGroups>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Для набора кадров ObjectAnimationUsingKeyFrames можно использовать несколько DiscreteObjectKeyFrame. Это может быть интересным способом создания анимации "слайд-шоу", анимируя значение Image.Source, в качестве примера сценария, в котором могут быть полезны несколько значений объектов.