緩動公式整理(附:C#實現及WPF原版對比)

leslie_xin發表於2020-09-22

前言

緩動在動畫效果中應用非常廣泛,在合適的時候使用一些緩動效果會使得效果更加符合人的直觀感受,簡單來說,會顯得更加自然。

WPF提供了11種緩動效果,涵蓋了大部分的使用場景。不過如果需要在非WPF下使用這些緩動效果,就需要知道對應的曲線公式了。因為公式是通用的,所以可以很輕鬆的使用其他語言實現。

由於本人數學水平有限,所以本文注重的應用而不是原理。在本文中,將會使用C#去實現,並附上與WPF原版的對比效果。

本文參考:

1,https://docs.microsoft.com/zh-cn/dotnet/desktop/wpf/graphics-multimedia/easing-functions?view=netframeworkdesktop-4.8

2,https://github.com/ai/easings.net

文末會附上示例原始碼,需要者可自行下載。

本文地址:https://www.cnblogs.com/lesliexin/p/13594811.html

 


 

一、WPF中的緩動效果

在WPF中,共有11種:Back,Bounce,Circle,Quadratic,Cubic,Quartic,Quintic,Elastic,Exponential,Sine,Power。不過嚴格來說只有7種,因為Quadratic,Cubic,Quartic,Quintic是由Power去實現的,由於Power引數未定,所以僅實現前10種效果。

所以對於每個緩動效果而言,都有三種模式:緩入(EaseIn)、緩出(EaseOut)、緩入緩出(EaseInOut)。

 


 

二、公式與動畫

一個元素的動畫效果,其實就是這個元素變化的快慢,也就是速度。速度與時間間隔和該時間間隔內運動距離兩個變數有關。在實際實現中,時間間隔是相等的,那麼速度的變化與距離的變化就成正比。在一個二維座標當中,橫座標為時間,縱座標為距離,那麼其形成的曲線中,曲線越陡,速度越快,曲線越平緩,則速度越慢。

而我們使用公式的目的,就是取得這個縱座標的值。

不過,要注意的是,我們獲取的曲線的時間範圍是:0~1,這不是具體的1秒或1毫秒,而是“單位1”。舉例來說,如果一個動畫效果時長是2000ms,那麼在第x ms時,對應的單位時間就是x/2000。

 


 

三、緩動公式、緩動效果、與WPF對比

1,Back

曲線(圖源自MSDN):

 

1.1,曲線公式

 

緩動公式整理(附:C#實現及WPF原版對比)
public static double Back(double x, LEaseMode easeMode)
{
    switch (easeMode)
    {
        case LEaseMode.EaseIn:
            return 2.70158 * x * x * x - 1.70158 * x * x;
        case LEaseMode.EaseOut:
            return 1 + 2.70158 * Math.Pow(x - 1, 3) + 1.70158 * Math.Pow(x - 1, 2);
        case LEaseMode.EaseInOut:
            return x < 0.5 ? (Math.Pow(2 * x, 2) * (7.189819 * x - 2.5949095)) / 2 : (Math.Pow(2 * x - 2, 2) * (7.189819 * x - 4.5949095) + 2) / 2;
        default:
            return 0;
    }
}
Back

 

1.2,WinForm效果

 

a,EaseIn:

b,EaseOut:

c,EaseInOut:

1.3,WPF效果

(上面矩形為WPF原版緩動效果,下面矩形為公式實現效果)

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

  

2,Bounce

曲線(圖源自MSDN):

 

2.1,曲線公式

 

緩動公式整理(附:C#實現及WPF原版對比)
private static double BounceOut(double x)
{
    if (x < 1d / 2.75d) return 7.5625 * x * x;
    else if (x < 2d / 2.75d) return 7.5625 * (x -= 1.5d / 2.75d) * x + 0.75;
    else if(x<2.5d/2.75d) return 7.5625 * (x -= 2.25d / 2.75d) * x + 0.9375;
    else return 7.5625 * (x -= 2.625d / 2.75d) * x + 0.984375;
}

public static double Bounce(double x, LEaseMode easeMode)
{
    switch (easeMode)
    {
        case LEaseMode.EaseIn:
            return 1 - BounceOut(1 - x);
        case LEaseMode.EaseOut:
            return BounceOut(x);
        case LEaseMode.EaseInOut:
            return x < 0.5 ? (1 - BounceOut(1 - 2 * x)) / 2 : (1 + BounceOut(2 * x - 1)) / 2;
        default:
            return 0;
    }
}
Bounce

 

2.2,WinForm效果

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

2.3,WPF效果

(上面矩形為WPF原版緩動效果,下面矩形為公式實現效果)

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

3,Circle

曲線(圖源自MSDN):

 

3.1,曲線公式

 

緩動公式整理(附:C#實現及WPF原版對比)
public static double Circle(double x, LEaseMode easeMode)
{
    switch (easeMode)
    {
        case LEaseMode.EaseIn:
            return 1 - Math.Sqrt(1 - Math.Pow(x, 2));
        case LEaseMode.EaseOut:
            return Math.Sqrt(1 - Math.Pow(x - 1, 2));
        case LEaseMode.EaseInOut:
            return x < 0.5 ? (1 - Math.Sqrt(1 - Math.Pow(2 * x, 2))) / 2 : (Math.Sqrt(1 - Math.Pow(-2 * x + 2, 2)) + 1) / 2;
        default:
            return 0;
    }
}
Circle

 

3.2,WinForm效果

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

3.3,WPF效果

(上面矩形為WPF原版緩動效果,下面矩形為公式實現效果)

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

4,Quadratic

曲線(圖源自MSDN):

 

4.1,曲線公式

 

緩動公式整理(附:C#實現及WPF原版對比)
public static double Power(double x,LEaseMode easeMode,int power)
{
    switch (easeMode)
    {
        case LEaseMode.EaseIn:
            return Math.Pow(x, power);
        case LEaseMode.EaseOut:
            return 1-Math.Pow(1-x,power);
        case LEaseMode.EaseInOut:
            return x < 0.5 ? Math.Pow(2,power-1)*Math.Pow(x,power) : 1 - Math.Pow(-2 * x + 2, power) / 2;
        default:
            return 0;
    }
}

public static double Quadratic(double x, LEaseMode easeMode)
{
    return Power(x, easeMode, 2);
}
Quadratic

 

4.2,WinForm效果

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

4.3,WPF效果

(上面矩形為WPF原版緩動效果,下面矩形為公式實現效果)

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

5,Cubic

曲線(圖源自MSDN):

 

5.1,曲線公式

 

緩動公式整理(附:C#實現及WPF原版對比)
public static double Power(double x,LEaseMode easeMode,int power)
{
    switch (easeMode)
    {
        case LEaseMode.EaseIn:
            return Math.Pow(x, power);
        case LEaseMode.EaseOut:
            return 1-Math.Pow(1-x,power);
        case LEaseMode.EaseInOut:
            return x < 0.5 ? Math.Pow(2,power-1)*Math.Pow(x,power) : 1 - Math.Pow(-2 * x + 2, power) / 2;
        default:
            return 0;
    }
}

public static double Cubic(double x, LEaseMode easeMode)
{
    return Power(x, easeMode, 3);
}
Cubic

 

5.2,WinForm效果

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

5.3,WPF效果

(上面矩形為WPF原版緩動效果,下面矩形為公式實現效果)

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

6,Quartic

曲線(圖源自MSDN):

 

6.1,曲線公式

 

緩動公式整理(附:C#實現及WPF原版對比)
public static double Power(double x,LEaseMode easeMode,int power)
{
    switch (easeMode)
    {
        case LEaseMode.EaseIn:
            return Math.Pow(x, power);
        case LEaseMode.EaseOut:
            return 1-Math.Pow(1-x,power);
        case LEaseMode.EaseInOut:
            return x < 0.5 ? Math.Pow(2,power-1)*Math.Pow(x,power) : 1 - Math.Pow(-2 * x + 2, power) / 2;
        default:
            return 0;
    }
}

public static double Quartic(double x, LEaseMode easeMode)
{
    return Power(x, easeMode,4);
}
Quartic

 

6.2,WinForm效果

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

6.3,WPF效果

(上面矩形為WPF原版緩動效果,下面矩形為公式實現效果)

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

7,Quintic

曲線(圖源自MSDN):

 

7.1,曲線公式

 

緩動公式整理(附:C#實現及WPF原版對比)
public static double Power(double x,LEaseMode easeMode,int power)
{
    switch (easeMode)
    {
        case LEaseMode.EaseIn:
            return Math.Pow(x, power);
        case LEaseMode.EaseOut:
            return 1-Math.Pow(1-x,power);
        case LEaseMode.EaseInOut:
            return x < 0.5 ? Math.Pow(2,power-1)*Math.Pow(x,power) : 1 - Math.Pow(-2 * x + 2, power) / 2;
        default:
            return 0;
    }
}

public static double Quintic(double x, LEaseMode easeMode)
{
    return Power(x, easeMode, 5);
}
Quintic

 

7.2,WinForm效果

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

7.3,WPF效果

(上面矩形為WPF原版緩動效果,下面矩形為公式實現效果)

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

8,Elastic

曲線(圖源自MSDN):

 

8.1,曲線公式

 

緩動公式整理(附:C#實現及WPF原版對比)
public static double Elastic(double x, LEaseMode easeMode)
{
    switch (easeMode)
    {
        case LEaseMode.EaseIn:
            return x == 0 ? 0 : x == 1 ? 1 : -Math.Pow(2, 10 * x - 10) * Math.Sin((x * 10 - 10.75) * 2 * Math.PI / 3);
        case LEaseMode.EaseOut:
            return x == 0 ? 0 : x == 1 ? 1 : Math.Pow(2, -10 * x) * Math.Sin((x * 10 - 0.75) * 2 * Math.PI / 3)+1;
        case LEaseMode.EaseInOut:
            return x == 0 ? 0 : x == 1 ? 1 : x < 0.5 ? -(Math.Pow(2, 20 * x - 10) * Math.Sin((x * 20 - 11.125) * 2 * Math.PI / 4.5)) / 2 : (Math.Pow(2, -20 * x + 10) * Math.Sin((x * 20 - 11.125) * 2 * Math.PI / 4.5)) / 2 + 1;
        default:
            return 0;
    }
}
Elastic

 

8.2,WinForm效果

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

8.3,WPF效果

(上面矩形為WPF原版緩動效果,下面矩形為公式實現效果)

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

9,Exponential

曲線(圖源自MSDN):

 

9.1,曲線公式

 

緩動公式整理(附:C#實現及WPF原版對比)
public static double Exponential(double x, LEaseMode easeMode)
{
    switch (easeMode)
    {
        case LEaseMode.EaseIn:
            return x == 0 ? 0 : Math.Pow(2, 10 * x - 10); 
        case LEaseMode.EaseOut:
            return x == 1 ? 1 : 1 - Math.Pow(2, -10 * x);
        case LEaseMode.EaseInOut:
            return x == 0 ? 0 : x == 1 ? 1 : x < 0.5 ? Math.Pow(2, 20 * x - 10) / 2 : (2 - Math.Pow(2, -20 * x + 10)) / 2;
        default:
            return 0;
    }
}
Exponential

 

9.2,WinForm效果

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

9.3,WPF效果

(上面矩形為WPF原版緩動效果,下面矩形為公式實現效果)

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

10,Sine

曲線(圖源自MSDN):

 

10.1,曲線公式

 

緩動公式整理(附:C#實現及WPF原版對比)
public static double Sine(double x, LEaseMode easeMode)
{
    switch (easeMode)
    {
        case LEaseMode.EaseIn:
            return 1 - Math.Cos((x * Math.PI) / 2);
        case LEaseMode.EaseOut:
            return Math.Sin((x * Math.PI) / 2);
        case LEaseMode.EaseInOut:
            return -(Math.Cos(Math.PI * x) - 1) / 2;
        default:
            return 0;
    }
}
Sine

 

10.2,WinForm效果

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

10.3,WPF效果

(上面矩形為WPF原版緩動效果,下面矩形為公式實現效果)

 

a,EaseIn:

 

b,EaseOut:

 

c,EaseInOut:

 

 


 

四、結束語

通過上面的動圖我們會發現,其中一些效果,使用公式生成的與WPF原版的是不一樣的,一是因為WPF原版的曲線不是固定的,還有其他引數去調控,而我對比的時候使用的是WPF預設的緩動效果;二是因為一像Bounce、Elastic等曲線以我的能力很難扒出來具體的公式,所以更多的是依照文首的Github上那個專案中的公式。所以難免有所差異。

 

同時,寫本篇文章是因為在之後的自定義控制元件系列文章,以及其他涉及圖形的文章中,會頻繁的使用緩動效果以增強直觀感受,到時文章中會引用本文所生成的類庫,當然也會隨文附上緩動公式。

 


 

五、原始碼下載

原始碼包含:

1,緩動類庫

2,WinForm演示

3,WPF演示

https://files.cnblogs.com/files/lesliexin/LEase.7z

 

相關文章