Skip to content

Commit

Permalink
Update docs animations (#9746)
Browse files Browse the repository at this point in the history
* Some Animation classes

* Update Animation.cs

* Fix comments

* Back to indented namespaces

* Update Animation.cs

* Update Animation.cs

* Update Animation.cs
  • Loading branch information
jfversluis authored Sep 30, 2022
1 parent 954f842 commit e33fc0f
Show file tree
Hide file tree
Showing 13 changed files with 359 additions and 82 deletions.
210 changes: 172 additions & 38 deletions src/Core/src/Animations/Animation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,27 @@

namespace Microsoft.Maui.Animations
{
/// <summary>
/// Represents an animation.
/// </summary>
public class Animation : IDisposable, IEnumerable
{
/// <summary>
/// Instantiate a new <see cref="Animation"/> object.
/// </summary>
public Animation()
{

}

/// <summary>
/// Instantiate a new <see cref="Animation"/> object with the given parameters.
/// </summary>
/// <param name="callback">The <see cref="Action{T}"/> that is invoked after each tick of this animation.</param>
/// <param name="start">Specifies a delay (in seconds) taken into account before the animation starts.</param>
/// <param name="duration">Specifies the duration that this animation should take in seconds.</param>
/// <param name="easing">The easing function to apply to this animation.</param>
/// <param name="finished">A callback <see cref="Action{T}"/> that is invoked after the animation has finished.</param>
public Animation(Action<double> callback, double start = 0.0f, double duration = 1.0f, Easing? easing = null, Action? finished = null)
{
StartDelay = start;
Expand All @@ -21,51 +36,122 @@ public Animation(Action<double> callback, double start = 0.0f, double duration =
Step = callback;

}

/// <summary>
/// Instantiate a new <see cref="Animation"/> object that consists of the given list of child animations.
/// </summary>
/// <param name="animations">A <see cref="List{T}"/> that contains <see cref="Animation"/> objects that will be children of the newly instantiated animation.</param>
public Animation(List<Animation> animations)
{
childrenAnimations = animations;
}

internal WeakReference<IAnimator>? Parent { get; set; }

/// <summary>
/// A callback that is invoked when this animation finishes.
/// </summary>
public Action? Finished { get; set; }

/// <summary>
/// A callback that is invoked after each tick of this animation.
/// </summary>
public Action<double>? Step { get; set; }
bool paused;
public bool IsPaused => paused;
protected List<Animation> childrenAnimations = new List<Animation>();

bool _paused;

/// <summary>
/// Specifies whether this animation is currently paused.
/// </summary>
public bool IsPaused => _paused;

/// <summary>
/// Collection of child animations associated to this animation.
/// </summary>
protected List<Animation> childrenAnimations = new();

/// <summary>
/// The name of this animation.
/// </summary>
public string? Name { get; set; }

/// <summary>
/// The delay (in seconds) taken into account before the animation starts.
/// </summary>
public double StartDelay { get; set; }

/// <summary>
/// The duration of this animation in seconds.
/// </summary>
public double Duration { get; set; }

/// <summary>
/// The current timestamp (in seconds) of the animation.
/// </summary>
public double CurrentTime { get; protected set; }

/// <summary>
/// Progress of this animation in percentage.
/// </summary>
public double Progress { get; protected set; }

/// <summary>
/// The <see cref="Easing"/> function that is applied to this animation.
/// </summary>
public Easing Easing { get; set; } = Easing.Default;

/// <summary>
/// Specifies whether this animation has finished.
/// </summary>
public bool HasFinished { get; protected set; }

/// <summary>
/// Specifies whether this animation should repeat.
/// </summary>
public bool Repeats { get; set; }

double _skippedSeconds;
int _usingResource = 0;

/// <summary>
/// Provides an <see cref="IEnumerator"/> of the child animations.
/// </summary>
/// <returns><see cref="IEnumerator"/> of <see cref="Animation"/></returns>
public IEnumerator GetEnumerator() => childrenAnimations.GetEnumerator();

/// <summary>
/// Adds a new child animation to this animation with the specified parameters.
/// </summary>
/// <param name="beginAt">Specifies a delay (in seconds) taken into account before the added child animation starts.</param>
/// <param name="duration">Specifies the duration (in seconds) that the added child animation should take.</param>
/// <param name="animation">The <see cref="Animation"/> object to add to this animation as a child.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="beginAt"/> or <paramref name="duration"/> is less than 0 or more than 1.</exception>
/// <exception cref="ArgumentException">Thrown when <paramref name="duration"/> is less than or equal to <paramref name="beginAt"/>.</exception>
public void Add(double beginAt, double duration, Animation animation)
{
if (beginAt < 0 || beginAt > 1)
throw new ArgumentOutOfRangeException("beginAt");
throw new ArgumentOutOfRangeException(nameof(beginAt));

if (duration < 0 || duration > 1)
throw new ArgumentOutOfRangeException("finishAt");
throw new ArgumentOutOfRangeException(nameof(duration));

if (duration <= beginAt)
throw new ArgumentException("finishAt must be greater than beginAt");
throw new ArgumentException($"{nameof(duration)} must be greater than {nameof(beginAt)}");

animation.StartDelay = beginAt;
animation.Duration = duration;
childrenAnimations.Add(animation);
}

/// <summary>
/// Method to trigger an update for this animation.
/// </summary>
/// <param name="milliseconds">Number of milliseconds that have passed since the last tick.</param>
public void Tick(double milliseconds)
{
if (IsPaused)
return;

if (0 == Interlocked.Exchange(ref _usingResource, 1))
{
try
Expand All @@ -85,15 +171,29 @@ public void Tick(double milliseconds)
_skippedSeconds += milliseconds;
}
}

/// <summary>
/// A reference to the <see cref="IAnimationManager"/> that manages this animation.
/// </summary>
public IAnimationManager? AnimationManager => animationManger;

/// <summary>
/// A reference to the <see cref="IAnimationManager"/> that manages this animation.
/// </summary>
protected IAnimationManager? animationManger;

/// <summary>
/// Executes the logic to update all animations within this animation.
/// </summary>
/// <param name="millisecondsSinceLastUpdate">Number of milliseconds that have passed since the last tick.</param>
protected virtual void OnTick(double millisecondsSinceLastUpdate)
{
if (HasFinished)
return;

var secondsSinceLastUpdate = millisecondsSinceLastUpdate / 1000.0;
CurrentTime += secondsSinceLastUpdate;

if (childrenAnimations.Any())
{
var hasFinished = true;
Expand All @@ -105,27 +205,33 @@ protected virtual void OnTick(double millisecondsSinceLastUpdate)
hasFinished = false;

}
HasFinished = hasFinished;


HasFinished = hasFinished;
}
else
{

var start = CurrentTime - StartDelay;

if (CurrentTime < StartDelay)
return;

var percent = Math.Min(start / Duration, 1);
Update(percent);
}

if (HasFinished)
{
Finished?.Invoke();

if (Repeats)
Reset();
}
}

/// <summary>
/// Updates this animation by updating <see cref="Progress"/> and invoking <see cref="Step"/>.
/// </summary>
/// <param name="percent">Progress of this animation in percentage.</param>
public virtual void Update(double percent)
{
try
Expand All @@ -141,105 +247,133 @@ public virtual void Update(double percent)
HasFinished = true;
}
}

/// <summary>
/// Sets the <see cref="IAnimationManager"/> for this animation.
/// </summary>
/// <param name="animationManger">Reference to the <see cref="IAnimationManager"/> that will manage this animation.</param>
public void Commit(IAnimationManager animationManger)
{
this.animationManger = animationManger;
animationManger.Add(this);

}

/// <summary>
/// Creates an animation that includes both the original animation and a reversed version of the same animation.
/// </summary>
/// <returns>An <see cref="Animation"/> object with the original animation and the reversed animation.</returns>
/// <remarks>You can get just the reversed animation by using <see cref="CreateReverse"/>.</remarks>
public Animation CreateAutoReversing()
{
var reveresedChildren = childrenAnimations.ToList();
reveresedChildren.Reverse();
var reveresed = CreateReverse();
var reversedChildren = childrenAnimations.ToList();
reversedChildren.Reverse();
var reversed = CreateReverse();

var parentAnimation = new Animation
{
Duration = reveresed.StartDelay + reveresed.Duration,
Duration = reversed.StartDelay + reversed.Duration,
Repeats = Repeats,
childrenAnimations =
{
this,
reveresed,
}
{
this,
reversed,
}
};

Repeats = false;
return parentAnimation;
}

/// <summary>
/// Creates a reversed version of the current animation, including reversing the child animations.
/// </summary>
/// <returns>An <see cref="Animation"/> object that is the reversed version of this animation.</returns>
/// <remarks>You can the forward and reverse animation by using <see cref="CreateAutoReversing"/>.</remarks>
protected virtual Animation CreateReverse()
{
var reveresedChildren = childrenAnimations.ToList();
reveresedChildren.Reverse();
var reversedChildren = childrenAnimations.ToList();
reversedChildren.Reverse();

return new Animation
{
Easing = Easing,
Duration = Duration,
StartDelay = StartDelay + Duration,
childrenAnimations = reveresedChildren,
childrenAnimations = reversedChildren,
};
}

/// <summary>
/// Resets the animation (and all child animations) to its initial state.
/// </summary>
public virtual void Reset()
{
CurrentTime = 0;
HasFinished = false;

foreach (var x in childrenAnimations)
x.Reset();
}

/// <summary>
/// Pauses the animation.
/// </summary>
public void Pause()
{
paused = true;
_paused = true;
animationManger?.Remove(this);
}

/// <summary>
/// Resumes the animation.
/// </summary>
public void Resume()
{
paused = false;
_paused = false;
animationManger?.Add(this);
}

/// <summary>
/// Removes this animation from it's <see cref="Parent"/>.
/// If there is no <see cref="Parent"/>, nothing will happen.
/// </summary>
public void RemoveFromParent()
{
IAnimator? view = null;
if (this.Parent?.TryGetTarget(out view) ?? false)
if (Parent?.TryGetTarget(out view) ?? false)
view?.RemoveAnimation(this);
}

/// <inheritdoc/>
public bool IsDisposed => _disposedValue;

private bool _disposedValue = false; // To detect redundant calls



#region IDisposable Support
public bool IsDisposed => disposedValue;


private bool disposedValue = false; // To detect redundant calls

/// <inheritdoc/>
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
if (!_disposedValue)
{
if (disposing)
{
foreach (var child in childrenAnimations)
child.Dispose();

childrenAnimations.Clear();
}
disposedValue = true;

_disposedValue = true;
animationManger?.Remove(this);
Finished = null;
Step = null;
}
}


// This code added to correctly implement the disposable pattern.
/// <inheritdoc/>
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
}

#endregion
}
}
Loading

0 comments on commit e33fc0f

Please sign in to comment.