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


Функции плавности

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

Кроме создания собственной функции плавности путем наследования от EasingFunctionBase, можно использовать одну из функций плавности, предоставляемых средой выполнения для создания распространенных эффектов.

  • BackEase: отзывает движение анимации незадолго до того, как она начнет выполняться в указанном пути.

  • BounceEase: создает эффект подпрыгивания.

  • CircleEase: создает анимацию, которая ускоряется и замедляется с помощью тригонометрической функции.

  • CubicEase: создает анимацию, которая ускоряется и замедляется с помощью формулы f(t) = t3.

  • ElasticEase: создает анимацию, похожую на колебательное движение пружины назад и вперед до полной остановки.

  • ExponentialEase: создает анимацию, которая ускоряется и замедляется с помощью экспоненциальной формулы.

  • PowerEase: создает анимацию, которая ускоряется и замедляется с помощью формулы f(t) = tp, где значение p равно значению свойства Power.

  • QuadraticEase: создает анимацию, которая ускоряется и замедляется с помощью формулы f(t) = t2.

  • QuarticEase: создает анимацию, которая ускоряется и замедляется с помощью формулы f(t) = t4.

  • QuinticEase: создает анимацию, которая ускоряется и замедляется с помощью формулы f(t) = t5.

  • SineEase: создает анимацию, которая ускоряется и замедляется с помощью формулы синуса.

С помощью следующего примера можно изучить поведение этих функций плавности.

Запустить этот пример

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

Запустить этот пример

<Rectangle Name="myRectangle" Width="200" Height="30" Fill="Blue">
    <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Rectangle.MouseDown">
            <BeginStoryboard>
                <Storyboard>
                    <Storyboard x:Name="myStoryboard">
                        <DoubleAnimation From="30" To="200" Duration="00:00:3" 
                         Storyboard.TargetName="myRectangle" 
                         Storyboard.TargetProperty="Height">
                            <DoubleAnimation.EasingFunction>
                                <BounceEase Bounces="2" EasingMode="EaseOut" 
                                 Bounciness="2" />
                            </DoubleAnimation.EasingFunction>
                        </DoubleAnimation>
                    </Storyboard>

                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Rectangle.Triggers>

</Rectangle>

В предыдущем примере функция плавности применялась к анимации From/To/By. Эти функции плавности можно также применять к анимациям по полным кадрам. В следующем примере показано использование ключевых кадров со связанными с ними функциями плавности для создания анимации прямоугольника, который сжимается снизу вверх, замедляется, затем расширяется сверху вниз (будто заполняется), а затем подпрыгивает до остановки.

Запустить этот пример

<Rectangle Name="myRectangle" Width="200" Height="200" Fill="Blue">
    <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Rectangle.MouseDown">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimationUsingKeyFrames
                     Storyboard.TargetProperty="Height"
                     Storyboard.TargetName="myRectangle">

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

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

                    </DoubleAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Rectangle.Triggers>

</Rectangle>

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

  • EaseIn, интерполяция производится по математической формуле, связанной с функцией плавности.

  • EaseOut: интерполяция производится по формуле, учитывающей 100-процентную интерполяцию за вычетом выходного значения формулы, связанной с функцией плавности.

  • EaseInOut: интерполяция использует EaseIn для первой половины анимации и EaseOut для второй половины.

На следующих диаграммах показаны различные значения EasingMode, где f(x), представляющие ход выполнения анимации и время представления t.

BackEase

Графы BackEase при различных значениях EasingMode.

BounceEase

Графы BounceEase при различных значениях EasingMode.

CircleEase

Графы CircleEase при различных значениях EasingMode.

CubicEase

Графы CubicEase при различных значениях EasingMode.

ElasticEase

Графы ElasticEase при различных значениях EasingMode.

ExponentialEase

Графы ExponentialEase при различных значениях EasingMode.

PowerEase

Графы QuarticEase при различных значениях EasingMode.

QuadraticEase

Графы QuadraticEase при различных значениях EasingMode

QuarticEase

Графы QuarticEase при различных значениях EasingMode.

QuinticEase

Графы QuinticEase при различных значениях EasingMode.

SineEase

Графы SineEase при различных значениях EasingMode

ПримечаниеПримечание

Можно использовать PowerEase для создания того же поведения, что и CubicEase, QuadraticEase, QuarticEase и QuinticEase с помощью свойства Power.Например, если планируется использовать PowerEase для подстановки CubicEase, следует указать значение свойства Power, равное 3.

Кроме использования функций округления, включенных в среду выполнения, можно создавать собственные функции округления, наследуя от EasingFunctionBase. В следующем примере показывается создание простой пользовательской функции округления. Можно добавить собственную математическую логику для поведения функции округления, переопределив метод EaseInCore.

Запустить этот пример

Namespace CustomEasingFunction
    Public Class CustomSeventhPowerEasingFunction
        Inherits EasingFunctionBase
        Public Sub New()
            MyBase.New()
        End Sub

        ' Specify your own logic for the easing function by overriding
        ' the EaseInCore method. Note that this logic applies to the "EaseIn"
        ' mode of interpolation. 
        Protected Overrides Function EaseInCore(ByVal normalizedTime As Double) As Double
            ' applies the formula of time to the seventh power.
            Return Math.Pow(normalizedTime, 7)
        End Function

        ' Typical implementation of CreateInstanceCore
        Protected Overrides Function CreateInstanceCore() As Freezable

            Return New CustomSeventhPowerEasingFunction()
        End Function

    End Class
End Namespace
namespace CustomEasingFunction
{
    public class CustomSeventhPowerEasingFunction : EasingFunctionBase
    {
        public CustomSeventhPowerEasingFunction()
            : base()
        {
        }

        // Specify your own logic for the easing function by overriding
        // the EaseInCore method. Note that this logic applies to the "EaseIn"
        // mode of interpolation. 
        protected override double EaseInCore(double normalizedTime)
        {
            // applies the formula of time to the seventh power.
            return Math.Pow(normalizedTime, 7);
        }

        // Typical implementation of CreateInstanceCore
        protected override Freezable CreateInstanceCore()
        {

            return new CustomSeventhPowerEasingFunction();
        }

    }
}
<Window x:Class="CustomEasingFunction.Window1"
        xmlns:CustomEase="clr-namespace:CustomEasingFunction"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="500" Width="300">
    <StackPanel>
        <TextBlock Margin="10" TextWrapping="Wrap">Click on the rectangle to start the animation</TextBlock>
        <StackPanel x:Name="LayoutRoot" Background="White">

            <Rectangle Name="myRectangle" Width="200" Height="30" Fill="Blue">
                <Rectangle.Triggers>
                    <EventTrigger RoutedEvent="Rectangle.MouseDown">
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation From="30" To="300" Duration="00:00:3" 
                                 Storyboard.TargetName="myRectangle" 
                                 Storyboard.TargetProperty="Height">
                                    <DoubleAnimation.EasingFunction>

                                        <!-- You get the EasingMode property for free on your custom
                                             easing function.-->
                                        <CustomEase:CustomSeventhPowerEasingFunction EasingMode="EaseIn"/>
                                    </DoubleAnimation.EasingFunction>
                                </DoubleAnimation>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </Rectangle.Triggers>

            </Rectangle>

        </StackPanel>
    </StackPanel>

</Window>