Browse Source

Simplify the animations iteration algorithm

pull/2163/head
Jumar Macato 8 years ago
parent
commit
52a9e72405
No known key found for this signature in database GPG Key ID: B19884DAC3A5BF3F
  1. 11
      src/Avalonia.Animation/Animation.cs
  2. 114
      src/Avalonia.Animation/AnimationInstance`1.cs

11
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 <see cref="DelayBetweenIterations"/> is set.
/// </remarks>
public TimeSpan Delay { get; set; }
public TimeSpan Delay { get; set; } = TimeSpan.Zero;
/// <summary>
/// Gets or sets a value indicating whether <see cref="Delay"/> will be applied between
/// iterations of the animation.
/// Gets or sets the amount of delay time between iterations.
/// </summary>
/// <remarks>
/// If this property is not set, then <see cref="Delay"/> will only be applied to the first
/// iteration of the animation.
/// </remarks>
public bool DelayBetweenIterations { get; set; }
public TimeSpan DelayBetweenIterations { get; set; } = TimeSpan.Zero;
private readonly static List<(Func<AvaloniaProperty, bool> Condition, Type Animator)> Animators = new List<(Func<AvaloniaProperty, bool>, Type)>
{

114
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<T> _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();
}
}
}
}
}
}
Loading…
Cancel
Save