diff --git a/src/Avalonia.Animation/Animation.cs b/src/Avalonia.Animation/Animation.cs
index 1ce9f5db06..ca1d97290e 100644
--- a/src/Avalonia.Animation/Animation.cs
+++ b/src/Avalonia.Animation/Animation.cs
@@ -254,7 +254,7 @@ namespace Avalonia.Animation
cue = new Cue(keyframe.KeyTime.TotalSeconds / Duration.TotalSeconds);
}
- var newKF = new AnimatorKeyFrame(handler, cue);
+ var newKF = new AnimatorKeyFrame(handler, cue, keyframe.KeySpline);
subscriptions.Add(newKF.BindSetter(setter, control));
diff --git a/src/Avalonia.Animation/AnimatorKeyFrame.cs b/src/Avalonia.Animation/AnimatorKeyFrame.cs
index 36d15e518e..f6a0c12be4 100644
--- a/src/Avalonia.Animation/AnimatorKeyFrame.cs
+++ b/src/Avalonia.Animation/AnimatorKeyFrame.cs
@@ -24,11 +24,20 @@ namespace Avalonia.Animation
{
AnimatorType = animatorType;
Cue = cue;
+ KeySpline = null;
+ }
+
+ public AnimatorKeyFrame(Type animatorType, Cue cue, KeySpline keySpline)
+ {
+ AnimatorType = animatorType;
+ Cue = cue;
+ KeySpline = keySpline;
}
internal bool isNeutral;
public Type AnimatorType { get; }
public Cue Cue { get; }
+ public KeySpline KeySpline { get; }
public AvaloniaProperty Property { get; private set; }
private object _value;
diff --git a/src/Avalonia.Animation/Animators/Animator`1.cs b/src/Avalonia.Animation/Animators/Animator`1.cs
index aa5e6aaf14..121ffda564 100644
--- a/src/Avalonia.Animation/Animators/Animator`1.cs
+++ b/src/Avalonia.Animation/Animators/Animator`1.cs
@@ -89,6 +89,9 @@ namespace Avalonia.Animation.Animators
else
newValue = (T)lastKeyframe.Value;
+ if (lastKeyframe.KeySpline != null) // TODO: do we use firstKeyFrame or lastKeyframe?!
+ progress = lastKeyframe.KeySpline.GetSplineProgress(progress);
+
return Interpolate(progress, oldValue, newValue);
}
diff --git a/src/Avalonia.Animation/KeyFrame.cs b/src/Avalonia.Animation/KeyFrame.cs
index ec59586584..c2cc1aa051 100644
--- a/src/Avalonia.Animation/KeyFrame.cs
+++ b/src/Avalonia.Animation/KeyFrame.cs
@@ -19,6 +19,7 @@ namespace Avalonia.Animation
{
private TimeSpan _ktimeSpan;
private Cue _kCue;
+ private KeySpline _kKeySpline;
public KeyFrame()
{
@@ -74,6 +75,25 @@ namespace Avalonia.Animation
}
}
+ ///
+ /// Gets or sets the KeySpline of this .
+ ///
+ /// The key spline.
+ public KeySpline KeySpline
+ {
+ get
+ {
+ return _kKeySpline;
+ }
+ set
+ {
+ _kKeySpline = value;
+ if (value != null && !value.IsValid())
+ {
+ throw new ArgumentException($"{nameof(KeySpline)} must have X coordinates >= 0.0 and <= 1.0.");
+ }
+ }
+ }
}
diff --git a/src/Avalonia.Animation/KeySpline.cs b/src/Avalonia.Animation/KeySpline.cs
index 34e8d89aae..dc6fb61744 100644
--- a/src/Avalonia.Animation/KeySpline.cs
+++ b/src/Avalonia.Animation/KeySpline.cs
@@ -66,7 +66,17 @@ namespace Avalonia.Animation
public double ControlPointX1
{
get => _controlPointX1;
- set => _controlPointX1 = value;
+ set
+ {
+ if (IsValidXValue(value))
+ {
+ _controlPointX1 = value;
+ }
+ else
+ {
+ throw new ArgumentException("Invalid KeySpline X1 value. Must be >= 0.0 and <= 1.0.");
+ }
+ }
}
public double ControlPointY1
@@ -78,7 +88,17 @@ namespace Avalonia.Animation
public double ControlPointX2
{
get => _controlPointX2;
- set => _controlPointX2 = value;
+ set
+ {
+ if (IsValidXValue(value))
+ {
+ _controlPointX2 = value;
+ }
+ else
+ {
+ throw new ArgumentException("Invalid KeySpline X2 value. Must be >= 0.0 and <= 1.0.");
+ }
+ }
}
public double ControlPointY2
@@ -94,8 +114,6 @@ namespace Avalonia.Animation
/// the spline progress
public double GetSplineProgress(double linearProgress)
{
- //ReadPreamble();
-
if (_isDirty)
{
Build();
@@ -113,6 +131,16 @@ namespace Avalonia.Animation
}
}
+ public bool IsValid()
+ {
+ return IsValidXValue(_controlPointX1) && IsValidXValue(_controlPointX2);
+ }
+
+ private bool IsValidXValue(double value)
+ {
+ return value >= 0.0 && value <= 1.0;
+ }
+
///
/// Compute cached coefficients.
///