diff --git a/src/Avalonia.Animation/Animation.cs b/src/Avalonia.Animation/Animation.cs index d7efc69e10..8b5e760455 100644 --- a/src/Avalonia.Animation/Animation.cs +++ b/src/Avalonia.Animation/Animation.cs @@ -54,17 +54,12 @@ namespace Avalonia.Animation /// Describes a delay to be added before the animation starts, and optionally between /// repeats of the animation if is set. /// - public TimeSpan Delay { get; set; } + public TimeSpan Delay { get; set; } = TimeSpan.Zero; /// - /// Gets or sets a value indicating whether will be applied between - /// iterations of the animation. + /// Gets or sets the amount of delay time between iterations. /// - /// - /// If this property is not set, then will only be applied to the first - /// iteration of the animation. - /// - public bool DelayBetweenIterations { get; set; } + public TimeSpan DelayBetweenIterations { get; set; } = TimeSpan.Zero; private readonly static List<(Func Condition, Type Animator)> Animators = new List<(Func, Type)> { diff --git a/src/Avalonia.Animation/AnimationInstance`1.cs b/src/Avalonia.Animation/AnimationInstance`1.cs index 52cb9e72c0..69b99f7888 100644 --- a/src/Avalonia.Animation/AnimationInstance`1.cs +++ b/src/Avalonia.Animation/AnimationInstance`1.cs @@ -15,18 +15,18 @@ namespace Avalonia.Animation { private T _lastInterpValue; private T _firstKFValue; - private long _repeatCount; + private float _iterationCount; private long _currentIteration; private bool _isLooping; private bool _gotFirstKFValue; - private bool _iterationDelay; private FillMode _fillMode; private PlaybackDirection _animationDirection; private Animator _parent; private Animatable _targetControl; private T _neutralValue; private double _speedRatio; - private TimeSpan _delay; + private TimeSpan _initialDelay; + private TimeSpan _iterationDelay; private TimeSpan _duration; private Easings.Easing _easeFunc; private Action _onCompleteAction; @@ -50,20 +50,20 @@ namespace Avalonia.Animation _speedRatio = animation.SpeedRatio; - _delay = animation.Delay; + _initialDelay = animation.Delay; _duration = animation.Duration; _iterationDelay = animation.DelayBetweenIterations; switch (animation.RepeatCount.RepeatType) { case RepeatType.None: - _repeatCount = 1; + _iterationCount = 1; break; case RepeatType.Loop: - _isLooping = true; + _iterationCount = float.PositiveInfinity; break; case RepeatType.Repeat: - _repeatCount = (long)animation.RepeatCount.Value; + _iterationCount = animation.RepeatCount.Value; break; } @@ -76,7 +76,7 @@ namespace Avalonia.Animation protected override void Unsubscribed() { - //Animation may have been stopped before it has finished + // Animation may have been stopped before it has finished. ApplyFinalFill(); _timerSubscription?.Dispose(); @@ -138,83 +138,51 @@ namespace Avalonia.Animation private void InternalStep(TimeSpan time) { DoPlayStates(); - var delayEndpoint = _delay; - var iterationEndpoint = delayEndpoint + _duration; - var iterationTime = time; - //determine if time is currently in the first iteration. - if (time >= TimeSpan.Zero & time <= iterationEndpoint) - { - _currentIteration = 1; - } - // time is currently the second to nth iteration. - else if (time > iterationEndpoint) - { - // Subtract first iteration to properly get the subsequent iteration time. - iterationTime -= iterationEndpoint; - - // Ignore delays on subsequent iterations if it's not the initial - // iteration unless _iterationDelay is enabled. - if (!_iterationDelay & delayEndpoint > TimeSpan.Zero) - { - delayEndpoint = TimeSpan.Zero; - iterationEndpoint = _duration; - } + var indexTime = time.Ticks; + var iterDuration = _duration.Ticks * _speedRatio; + var iterDelay = _iterationDelay.Ticks * _speedRatio; + var initDelay = _initialDelay.Ticks * _speedRatio; - // Calculate the current iteration number - _currentIteration = (iterationTime.Ticks / iterationEndpoint.Ticks) + 2; - } - else + if (indexTime > 0 & indexTime <= initDelay) { - return; + DoDelay(); } - - // Determine if the current iteration should have its normalized time reversed. - bool isCurIterReverse = _animationDirection == PlaybackDirection.Normal ? false : - _animationDirection == PlaybackDirection.Alternate ? (_currentIteration % 2 == 0) ? false : true : - _animationDirection == PlaybackDirection.AlternateReverse ? (_currentIteration % 2 == 0) ? true : false : - _animationDirection == PlaybackDirection.Reverse ? true : false; - - if (!_isLooping) + else { - var totalTime = _iterationDelay ? _repeatCount * (_duration.Ticks + _delay.Ticks) : _repeatCount * _duration.Ticks + _delay.Ticks; - - // Clamp value when animations ends. - if (time.Ticks >= totalTime) - { - var easedTime = _easeFunc.Ease(isCurIterReverse ? 0.0 : 1.0); - _lastInterpValue = _interpolator(easedTime, _neutralValue); + var fullIterationTime = iterDuration + iterDelay; + var opsTime = indexTime - initDelay; + var playbackTime = opsTime % fullIterationTime; + _currentIteration = (long)Math.Floor(opsTime / fullIterationTime); + + if ((_currentIteration + 1) > _iterationCount) DoComplete(); - return; - } - } - iterationTime = TimeSpan.FromTicks(iterationTime.Ticks % iterationEndpoint.Ticks); - - if (delayEndpoint > TimeSpan.Zero & iterationTime < delayEndpoint) - { - DoDelay(); - } - else - { - // Offset the delay time - iterationTime -= delayEndpoint; - iterationEndpoint -= delayEndpoint; + if (playbackTime <= iterDuration) + { + var normalizedTime = playbackTime / iterDuration; - // Normalize time - var interpVal = (double)iterationTime.Ticks / iterationEndpoint.Ticks; + bool isCurIterReverse = _animationDirection == PlaybackDirection.Normal ? false : + _animationDirection == PlaybackDirection.Alternate ? (_currentIteration % 2 == 0) ? false : true : + _animationDirection == PlaybackDirection.AlternateReverse ? (_currentIteration % 2 == 0) ? true : false : + _animationDirection == PlaybackDirection.Reverse ? true : false; - // Check if normalized time needs to be reversed. - if (isCurIterReverse) - interpVal = 1 - interpVal; + // Check if normalized time needs to be reversed. + if (isCurIterReverse) + normalizedTime = 1 - normalizedTime; - // Ease and interpolate - var easedTime = _easeFunc.Ease(interpVal); - _lastInterpValue = _interpolator(easedTime, _neutralValue); + // Ease and interpolate + var easedTime = _easeFunc.Ease(normalizedTime); + _lastInterpValue = _interpolator(easedTime, _neutralValue); - PublishNext(_lastInterpValue); + PublishNext(_lastInterpValue); + } + else if (playbackTime > iterDuration & playbackTime <= fullIterationTime & iterDelay > 0) + { + DoDelay(); + } } } } -} +} \ No newline at end of file