| File: Animations\AnimationManager.cs | Web Access |
| Project: src\src\Core\src\Core.csproj (Microsoft.Maui) |
using System; using System.Collections.Generic; namespace Microsoft.Maui.Animations { /// <inheritdoc/> public class AnimationManager : IAnimationManager, IDisposable { readonly List<Animation> _animations = new(); long _lastUpdate; bool _disposedValue; /// <summary> /// Instantiate a new <see cref="AnimationManager"/> object. /// </summary> /// <param name="ticker">An instance of <see cref="ITicker"/> that will be used to time the animations.</param> public AnimationManager(ITicker ticker) { _lastUpdate = GetCurrentTick(); Ticker = ticker; Ticker.Fire = OnFire; } /// <inheritdoc/> public ITicker Ticker { get; } /// <inheritdoc/> public double SpeedModifier { get; set; } = 1; /// <inheritdoc/> public bool AutoStartTicker { get; set; } = true; /// <inheritdoc/> public void Add(Animation animation) { // If animations are disabled, don't do anything if (!Ticker.SystemEnabled) { return; } if (!_animations.Contains(animation)) _animations.Add(animation); if (!Ticker.IsRunning && AutoStartTicker) Start(); } /// <inheritdoc/> public void Remove(Animation animation) { _animations.TryRemove(animation); if (_animations.Count == 0) End(); } void Start() { _lastUpdate = GetCurrentTick(); Ticker.Start(); } void End() => Ticker?.Stop(); static long GetCurrentTick() => Environment.TickCount & int.MaxValue; void OnFire() { if (!Ticker.SystemEnabled) { // This is a hack - if we're here, the ticker has detected that animations are no longer enabled, // and it's invoked the Fire event one last time because that's the only communication mechanism // it currently has available with the AnimationManager. We need to force all the running animations // to move to their finished state and stop running. ForceFinishAnimations(); return; } var now = GetCurrentTick(); var milliseconds = TimeSpan.FromMilliseconds(now - _lastUpdate).TotalMilliseconds; _lastUpdate = now; var animations = new List<Animation>(_animations); animations.ForEach(OnAnimationTick); if (_animations.Count == 0) End(); void OnAnimationTick(Animation animation) { if (animation.HasFinished) { _animations.TryRemove(animation); animation.RemoveFromParent(); return; } animation.Tick(AdjustSpeed(milliseconds)); if (animation.HasFinished) { _animations.TryRemove(animation); animation.RemoveFromParent(); } } } protected virtual void Dispose(bool disposing) { if (!_disposedValue) { if (disposing && Ticker is IDisposable disposable) disposable.Dispose(); _disposedValue = true; } } /// <inheritdoc/> public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } void ForceFinishAnimations() { var animations = new List<Animation>(_animations); animations.ForEach(ForceFinish); End(); void ForceFinish(Animation animation) { animation.ForceFinish(); _animations.TryRemove(animation); animation.RemoveFromParent(); } } internal virtual double AdjustSpeed(double elapsedMilliseconds) { return elapsedMilliseconds * SpeedModifier; } } }