From 5f4a38842c37693a783712ba2116efbdeeec7217 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Thu, 6 Sep 2018 13:26:17 +0800 Subject: [PATCH] Finally fixed the flickering heart bug! Simplify the Keyframe selection and removed all LINQ code. Use the Cue property on AnimatorKeyFrame as the time index and integrate the IsNeutral value as an internal property. --- src/Avalonia.Animation/AnimatorKeyFrame.cs | 1 + src/Avalonia.Animation/Animator`1.cs | 61 ++++++++++++++-------- src/Avalonia.Animation/Cue.cs | 5 +- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/Avalonia.Animation/AnimatorKeyFrame.cs b/src/Avalonia.Animation/AnimatorKeyFrame.cs index 0276c6fa92..0dc15da49c 100644 --- a/src/Avalonia.Animation/AnimatorKeyFrame.cs +++ b/src/Avalonia.Animation/AnimatorKeyFrame.cs @@ -29,6 +29,7 @@ namespace Avalonia.Animation Cue = cue; } + internal bool isNeutral; public Type AnimatorType { get; } public Cue Cue { get; } public AvaloniaProperty Property { get; private set; } diff --git a/src/Avalonia.Animation/Animator`1.cs b/src/Avalonia.Animation/Animator`1.cs index 8079ac69b5..7631a11d9c 100644 --- a/src/Avalonia.Animation/Animator`1.cs +++ b/src/Avalonia.Animation/Animator`1.cs @@ -19,7 +19,7 @@ namespace Avalonia.Animation /// /// List of type-converted keyframes. /// - private readonly SortedList _convertedKeyframes = new SortedList(); + private readonly List _convertedKeyframes = new List(); private bool isVerfifiedAndConverted; @@ -58,41 +58,49 @@ namespace Avalonia.Animation /// The time parameter, relative to the total animation time protected (double IntraKFTime, KeyFramePair KFPair) GetKFPairAndIntraKFTime(double t) { - KeyValuePair firstCue, lastCue; + AnimatorKeyFrame firstCue, lastCue ; int kvCount = _convertedKeyframes.Count; if (kvCount > 2) { if (DoubleUtils.AboutEqual(t, 0.0) || t < 0.0) { - firstCue = _convertedKeyframes.First(); - lastCue = _convertedKeyframes.Skip(1).First(); + firstCue = _convertedKeyframes[0]; + lastCue = _convertedKeyframes[1]; } else if (DoubleUtils.AboutEqual(t, 1.0) || t > 1.0) { - firstCue = _convertedKeyframes.Skip(kvCount - 2).First(); - lastCue = _convertedKeyframes.Last(); + firstCue = _convertedKeyframes[_convertedKeyframes.Count - 2]; + lastCue = _convertedKeyframes[_convertedKeyframes.Count - 1]; } else { - firstCue = _convertedKeyframes.Last(j => j.Key <= t); - lastCue = _convertedKeyframes.First(j => j.Key >= t); + (double time, int index) maxval = (0.0d, 0); + for (int i = 0; i < _convertedKeyframes.Count; i++) + { + var comp = _convertedKeyframes[i].Cue.CueValue; + if (t >= comp) + { + maxval = (comp, i); + } + } + firstCue = _convertedKeyframes[maxval.index]; + lastCue = _convertedKeyframes[maxval.index + 1]; } } else { - firstCue = _convertedKeyframes.First(); - lastCue = _convertedKeyframes.Last(); + firstCue = _convertedKeyframes[0]; + lastCue = _convertedKeyframes[1]; } - double t0 = firstCue.Key; - double t1 = lastCue.Key; + double t0 = firstCue.Cue.CueValue; + double t1 = lastCue.Cue.CueValue; var intraframeTime = (t - t0) / (t1 - t0); - var firstFrameData = (firstCue.Value.frame.GetTypedValue(), firstCue.Value.isNeutral); - var lastFrameData = (lastCue.Value.frame.GetTypedValue(), lastCue.Value.isNeutral); + var firstFrameData = (firstCue.GetTypedValue(), firstCue.isNeutral); + var lastFrameData = (lastCue.GetTypedValue(), lastCue.isNeutral); return (intraframeTime, new KeyFramePair(firstFrameData, lastFrameData)); } - /// /// Runs the KeyFrames Animation. /// @@ -113,16 +121,25 @@ namespace Avalonia.Animation protected abstract T DoInterpolation(double time, T neutralValue); /// - /// Verifies and converts keyframe values according to this class's target type. + /// Verifies, converts and sorts keyframe values according to this class's target type. /// private void VerifyConvertKeyFrames() { foreach (AnimatorKeyFrame keyframe in this) { - _convertedKeyframes.Add(keyframe.Cue.CueValue, (keyframe, false)); + _convertedKeyframes.Add(keyframe); } AddNeutralKeyFramesIfNeeded(); + + var copy = _convertedKeyframes.ToList().OrderBy(p => p.Cue.CueValue); + _convertedKeyframes.Clear(); + + foreach (AnimatorKeyFrame keyframe in copy) + { + _convertedKeyframes.Add(keyframe); + } + isVerfifiedAndConverted = true; } @@ -133,13 +150,13 @@ namespace Avalonia.Animation hasStartKey = hasEndKey = false; // Check if there's start and end keyframes. - foreach (var converted in _convertedKeyframes.Keys) + foreach (var frame in _convertedKeyframes) { - if (DoubleUtils.AboutEqual(converted, 0.0)) + if (DoubleUtils.AboutEqual(frame.Cue.CueValue, 0.0)) { hasStartKey = true; } - else if (DoubleUtils.AboutEqual(converted, 1.0)) + else if (DoubleUtils.AboutEqual(frame.Cue.CueValue, 1.0)) { hasEndKey = true; } @@ -153,12 +170,12 @@ namespace Avalonia.Animation { if (!hasStartKey) { - _convertedKeyframes.Add(0.0d, (new AnimatorKeyFrame { Value = default(T) }, true)); + _convertedKeyframes.Add(new AnimatorKeyFrame(null, new Cue(0.0d)) { Value = default(T), isNeutral = true }); } if (!hasEndKey) { - _convertedKeyframes.Add(1.0d, (new AnimatorKeyFrame { Value = default(T) }, true)); + _convertedKeyframes.Add(new AnimatorKeyFrame(null, new Cue(1.0d)) { Value = default(T), isNeutral = true }); } } } diff --git a/src/Avalonia.Animation/Cue.cs b/src/Avalonia.Animation/Cue.cs index 5a95c108e3..de77475c2c 100644 --- a/src/Avalonia.Animation/Cue.cs +++ b/src/Avalonia.Animation/Cue.cs @@ -7,7 +7,7 @@ using System.Text; namespace Avalonia.Animation { /// - /// A Cue object for . + /// Determines the time index for a . /// [TypeConverter(typeof(CueTypeConverter))] public readonly struct Cue : IEquatable, IEquatable @@ -84,5 +84,4 @@ namespace Avalonia.Animation return Cue.Parse((string)value, culture); } } - -} +} \ No newline at end of file