Bladeren bron

Implement IterationTokens for Repeat behaviors

Jumar Macato 7 jaren geleden
bovenliggende
commit
df602f8480

+ 22 - 14
src/Avalonia.Animation/Animatable.cs

@@ -24,6 +24,7 @@ namespace Avalonia.Animation
         public Animatable()
         {
             Transitions = new Transitions.Transitions();
+            _animationStates = new Dictionary<ulong, AnimationStatus>();
             AnimatableTimer = Timing.AnimationStateTimer
                          .Select(p =>
                          {
@@ -37,34 +38,40 @@ namespace Avalonia.Animation
                          .RefCount();
         }
 
+
         /// <summary>
         /// The specific animations timer for this control.
         /// </summary>
         /// <returns></returns>
         public IObservable<ulong> AnimatableTimer;
 
-        internal void PrepareAnimatableForAnimation()
+        internal class AnimationStatus
         {
-            if (!_animationsInitialized)
-            {
+            public int RepeatCount { get; set; }
+            public int IterationDirection { get; set; }
+            public int CurrentIteration { get; set; }
+            public int TotalIteration { get; set; }
+        }
 
+        internal Dictionary<ulong, AnimationStatus> _animationStates;
 
-                _animationsInitialized = true;
-            }
+        internal ulong PrepareAnimatableForAnimation()
+        {
+            var iterToken = GetIterationToken();
+            _animationStates.Add(iterToken, new AnimationStatus());
+            return iterToken;
         }
 
         bool _animationsInitialized = false;
 
-        // internal ConcurrentDictionary<int, (int repeatCount, int direction)> _animationStates;
-
         internal ulong _animationTime;
-        
-        // internal int _iterationTokenCounter;
 
-        // internal uint GetIterationToken()
-        // {
-        //     return (uint)Interlocked.Increment(ref _iterationTokenCounter);
-        // }
+        internal ulong _iterationTokenCounter;
+
+        internal ulong GetIterationToken()
+        {
+            return _iterationTokenCounter++;
+        }
 
         /// <summary>
         /// Defines the <see cref="PlayState"/> property.
@@ -75,6 +82,8 @@ namespace Avalonia.Animation
                 o => o.PlayState,
                 (o, v) => o.PlayState = v);
 
+        private PlayState _playState = PlayState.Run;
+
         /// <summary>
         /// Gets or sets the state of the animation for this
         /// control.
@@ -86,7 +95,6 @@ namespace Avalonia.Animation
 
         }
 
-        private PlayState _playState = PlayState.Run;
 
         /// <summary>
         /// Defines the <see cref="Transitions"/> property.

+ 3 - 3
src/Avalonia.Animation/Animation.cs

@@ -64,11 +64,11 @@ namespace Avalonia.Animation
         /// <inheritdocs/>
         public IDisposable Apply(Animatable control, IObservable<bool> matchObs)
         {
-            control.PrepareAnimatableForAnimation();
-            
+            var iterToken = control.PrepareAnimatableForAnimation();
+
             foreach (IKeyFrames keyframes in Children)
             {
-                _subscription.Add(keyframes.Apply(this, control, matchObs));
+                _subscription.Add(keyframes.Apply(this, control, iterToken, matchObs));
             }
             return this;
         }

+ 10 - 12
src/Avalonia.Animation/Keyframes/DoubleKeyFrames.cs

@@ -14,23 +14,21 @@ namespace Avalonia.Animation.Keyframes
     /// </summary>
     public class DoubleKeyFrames : KeyFrames<double>
     {
-
         /// <inheritdocs/>
-        public override IObservable<double> DoInterpolation(Animation animation, Animatable control)
-            => SetupAnimation(animation, control)
-              .Select(t =>
-              {
+        public override IObservable<double> DoInterpolation(IObservable<double> timer, Animation animation, Animatable control)
+          => timer.Select(t =>
+             {
                   // Get a pair of keyframes to make the interpolation.
-                  var pair = GetKeyFramePairByTime(t.Time);
+                  var pair = GetKeyFramePairByTime(t);
 
-                  double y0 = pair.FirstKeyFrame.Value;
-                  double t0 = pair.FirstKeyFrame.Key;
-                  double y1 = pair.SecondKeyFrame.Value;
-                  double t1 = pair.SecondKeyFrame.Key;
+                 double y0 = pair.FirstKeyFrame.Value;
+                 double t0 = pair.FirstKeyFrame.Key;
+                 double y1 = pair.SecondKeyFrame.Value;
+                 double t1 = pair.SecondKeyFrame.Key;
 
                   // Do linear parametric interpolation 
-                  return y0 + ((t.Time - t0) / (t1 - t0)) * (y1 - y0);
-              });
+                  return y0 + ((t - t0) / (t1 - t0)) * (y1 - y0);
+             });
 
     }
 }

+ 1 - 1
src/Avalonia.Animation/Keyframes/IKeyFrames.cs

@@ -12,6 +12,6 @@ namespace Avalonia.Animation.Keyframes
         /// <summary>
         /// Applies the current KeyFrame group to the specified control.
         /// </summary>
-        IDisposable Apply(Animation animation, Animatable control, IObservable<bool> obsMatch);
+        IDisposable Apply(Animation animation, Animatable control, ulong IterationToken, IObservable<bool> obsMatch);
     }
 }

+ 11 - 8
src/Avalonia.Animation/Keyframes/KeyFrames.cs

@@ -31,7 +31,7 @@ namespace Avalonia.Animation.Keyframes
 
 
         /// <inheritdoc/>
-        public virtual IDisposable Apply(Animation animation, Animatable control, IObservable<bool> obsMatch)
+        public virtual IDisposable Apply(Animation animation, Animatable control, ulong IterationToken, IObservable<bool> obsMatch)
         {
             if (!IsVerfifiedAndConverted)
                 VerifyConvertKeyFrames(animation, typeof(T));
@@ -39,10 +39,11 @@ namespace Avalonia.Animation.Keyframes
             return obsMatch
                 .Where(p => p == true)
                 // Ignore triggers when global timers are paused.
-                .Where(p=> Timing.GetGlobalPlayState() == PlayState.Run)
+                .Where(p => Timing.GetGlobalPlayState() == PlayState.Run)
                 .Subscribe(_ =>
                 {
-                    var interp = DoInterpolation(animation, control)
+                    var timerObs = SetupAnimation(animation, control);
+                    var interp = DoInterpolation(timerObs, animation, control)
                                 .Select(p => (object)p);
 
                     control.Bind(Property, interp, BindingPriority.Animation);
@@ -88,15 +89,17 @@ namespace Avalonia.Animation.Keyframes
         /// Returns an observable timer with the specific Animation
         /// duration and delay and applies the Animation's easing function.
         /// </summary>
-        public IObservable<(double Time, Animatable Target)> 
-            SetupAnimation(Animation animation, Animatable control) =>
-                        Timing.GetAnimationsTimer(control, animation.Duration, animation.Delay)
-                              .Select(t => (animation.Easing.Ease(t), control));
+        public IObservable<double> SetupAnimation(Animation animation, Animatable control)
+        {
+            var newTimer = Timing.GetAnimationsTimer(control, animation.Duration, animation.Delay);
+            return newTimer.Select(t => animation.Easing.Ease(t));
+        }
+
 
         /// <summary>
         /// Interpolates the given keyframes to the control.
         /// </summary>
-        public abstract IObservable<T> DoInterpolation(Animation animation,
+        public abstract IObservable<T> DoInterpolation(IObservable<double> timer, Animation animation,
                                                        Animatable control);
 
 

+ 9 - 11
src/Avalonia.Visuals/Animation/Keyframes/TransformKeyFrames.cs

@@ -18,7 +18,7 @@ namespace Avalonia.Animation.Keyframes
         DoubleKeyFrames childKeyFrames;
 
         /// <inheritdoc/>
-        public override IDisposable Apply(Animation animation, Animatable control, IObservable<bool> obsMatch)
+        public override IDisposable Apply(Animation animation, Animatable control, ulong IterationToken, IObservable<bool> obsMatch)
         {
             var ctrl = (Visual)control;
 
@@ -26,26 +26,25 @@ namespace Avalonia.Animation.Keyframes
             if (typeof(Transform).IsAssignableFrom(Property.OwnerType) && ctrl.RenderTransform != null)
             {
                 var renderTransformType = ctrl.RenderTransform.GetType();
-                
+
                 if (childKeyFrames == null)
                 {
                     InitializeInternalDoubleKeyFrames();
                 }
 
-                // It's only 1 transform object so let's target that.
+                // It's a transform object so let's target that.
                 if (renderTransformType == Property.OwnerType)
                 {
-                    return childKeyFrames.Apply(animation, ctrl.RenderTransform, obsMatch);
+                    return childKeyFrames.Apply(animation, ctrl.RenderTransform, IterationToken, obsMatch);
                 }
-                // Try if the control's RenderTransform is a TransformGroup and find 
-                // the target there.
+                // It's a TransformGroup and try finding the target there.
                 else if (renderTransformType == typeof(TransformGroup))
                 {
                     foreach (Transform transform in ((TransformGroup)ctrl.RenderTransform).Children)
                     {
                         if (transform.GetType() == Property.OwnerType)
                         {
-                            return childKeyFrames.Apply(animation, transform, obsMatch);
+                            return childKeyFrames.Apply(animation, transform, IterationToken, obsMatch);
                         }
                     }
                 }
@@ -74,9 +73,8 @@ namespace Avalonia.Animation.Keyframes
         }
 
         /// <inheritdocs/>
-        public override IObservable<double> DoInterpolation(Animation animation, Animatable control)
-        {
-            return null;
-        }
+        public override IObservable<double> DoInterpolation(IObservable<double> timer, Animation animation, Animatable control) => null;
+
+        
     }
 }