Skip to content

Commit 6d840ab

Browse files
committed
fix: Fix bounce ease producing invalid final value
1 parent 9794dd8 commit 6d840ab

File tree

2 files changed

+88
-22
lines changed

2 files changed

+88
-22
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Windows.UI.Xaml.Media.Animation;
7+
using FluentAssertions;
8+
using Microsoft.VisualStudio.TestTools.UnitTesting;
9+
10+
namespace Uno.UI.Tests.Windows_UI_Xaml_Media_Animation
11+
{
12+
[TestClass]
13+
public class Given_BounceEase
14+
{
15+
[TestMethod]
16+
public void When_FinalValueGreaterThanInitial()
17+
{
18+
var sut = new BounceEase();
19+
20+
EaseCore(0.0).Should().BeApproximately(100, .1);
21+
EaseCore(1.0).Should().BeApproximately(200, .1);
22+
23+
double EaseCore(double normalizedTime)
24+
=> sut.Ease(
25+
currentTime: normalizedTime, duration: 1.0,
26+
startValue: 100, finalValue: 200);
27+
}
28+
29+
[TestMethod]
30+
public void When_FinalValueLowerThanInitial()
31+
{
32+
var sut = new BounceEase();
33+
34+
EaseCore(0.0).Should().BeApproximately(200, .1);
35+
EaseCore(1.0).Should().BeApproximately(100, .1);
36+
37+
double EaseCore(double normalizedTime)
38+
=> sut.Ease(
39+
currentTime: normalizedTime, duration: 1.0,
40+
startValue: 200, finalValue: 100);
41+
}
42+
}
43+
}

src/Uno.UI/UI/Xaml/Media/Animation/BounceEase.cs

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,44 +6,67 @@ namespace Windows.UI.Xaml.Media.Animation
66
{
77
public partial class BounceEase : EasingFunctionBase
88
{
9+
// Source: https://easings.net/
10+
911
public override double Ease(double currentTime, double startValue, double finalValue, double duration)
1012
{
11-
//Depending on the mode we have different functions for the return value.
12-
switch (this.EasingMode)
13+
var delta = finalValue - startValue;
14+
var progress = currentTime / duration;
15+
16+
var ratio = EaseCore(progress);
17+
18+
return startValue + ratio * delta;
19+
}
20+
21+
internal double EaseCore(double progress)
22+
{
23+
switch (EasingMode)
1324
{
1425
case EasingMode.EaseIn:
15-
return BounceEaseIn(currentTime, startValue,finalValue, duration);
26+
return BounceEaseIn(progress);
1627

1728
case EasingMode.EaseOut:
18-
return BounceEaseOut(currentTime, startValue, finalValue, duration);
29+
return BounceEaseOut(progress);
1930

2031
case EasingMode.EaseInOut:
21-
22-
if (currentTime < duration / 2)
23-
return BounceEaseIn(currentTime * 2, 0, finalValue, duration) * .5 + startValue;
24-
else
25-
return BounceEaseOut(currentTime * 2 - duration, 0, finalValue, duration) * .5 + finalValue * .5 + startValue;
26-
2732
default:
28-
return finalValue * currentTime / duration + startValue;
33+
return BounceEaseInOut(progress);
2934
}
3035
}
3136

32-
public static double BounceEaseIn(double currentTime, double startValue, double finalValue, double duration)
37+
public static double BounceEaseIn(double progress)
3338
{
34-
return finalValue - BounceEaseOut(duration - currentTime, 0, finalValue, duration) + startValue;
39+
return 1 - BounceEaseOut(1 - progress);
3540
}
3641

37-
public static double BounceEaseOut(double currentTime, double startValue, double finalValue, double duration)
42+
public static double BounceEaseOut(double progress)
3843
{
39-
if ((currentTime /= duration) < (1 / 2.75))
40-
return finalValue * (7.5625 * currentTime * currentTime) + startValue;
41-
else if (currentTime < (2 / 2.75))
42-
return finalValue * (7.5625 * (currentTime -= (1.5 / 2.75)) * currentTime + .75) + startValue;
43-
else if (currentTime < (2.5 / 2.75))
44-
return finalValue * (7.5625 * (currentTime -= (2.25 / 2.75)) * currentTime + .9375) + startValue;
44+
const double n1 = 7.5625;
45+
const double d1 = 2.75;
46+
47+
if (progress < 1 / d1)
48+
{
49+
return n1 * progress * progress;
50+
}
51+
else if (progress < 2 / d1)
52+
{
53+
return n1 * (progress -= 1.5 / d1) * progress + 0.75;
54+
}
55+
else if (progress < 2.5 / d1)
56+
{
57+
return n1 * (progress -= 2.25 / d1) * progress + 0.9375;
58+
}
4559
else
46-
return finalValue * (7.5625 * (currentTime -= (2.625 / 2.75)) * currentTime + .984375) + startValue;
60+
{
61+
return n1 * (progress -= 2.625 / d1) * progress + 0.984375;
62+
}
4763
}
48-
}
64+
65+
public static double BounceEaseInOut(double progress)
66+
{
67+
return progress < 0.5
68+
? (1 - BounceEaseOut(1 - 2 * progress)) / 2
69+
: (1 + BounceEaseOut(2 * progress - 1)) / 2;
70+
}
71+
}
4972
}

0 commit comments

Comments
 (0)