|
|
@@ -1,6 +1,7 @@
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
-using System.Reactive.Disposables;
|
|
|
+using System.Diagnostics.CodeAnalysis;
|
|
|
+
|
|
|
using Avalonia.Logging;
|
|
|
using Avalonia.Media;
|
|
|
|
|
|
@@ -16,8 +17,6 @@ namespace Avalonia.Animation.Animators
|
|
|
/// </summary>
|
|
|
public class BaseBrushAnimator : Animator<IBrush?>
|
|
|
{
|
|
|
- private IAnimator? _targetAnimator;
|
|
|
-
|
|
|
private static readonly List<(Func<Type, bool> Match, Type AnimatorType)> _brushAnimators =
|
|
|
new List<(Func<Type, bool> Match, Type AnimatorType)>();
|
|
|
|
|
|
@@ -42,41 +41,127 @@ namespace Avalonia.Animation.Animators
|
|
|
public override IDisposable Apply(Animation animation, Animatable control, IClock clock,
|
|
|
IObservable<bool> match, Action onComplete)
|
|
|
{
|
|
|
- _targetAnimator = CreateAnimatorFromType(this[0].Value.GetType());
|
|
|
+ if (TryCreateCustomRegisteredAnimator(out var animator)
|
|
|
+ || TryCreateGradientAnimator(out animator)
|
|
|
+ || TryCreateSolidColorBrushAnimator(out animator))
|
|
|
+ {
|
|
|
+ return animator.Apply(animation, control, clock, match, onComplete);
|
|
|
+ }
|
|
|
+
|
|
|
+ Logger.TryGet(LogEventLevel.Error, LogArea.Animations)?.Log(
|
|
|
+ this,
|
|
|
+ "The animation's keyframe value types set is not supported.");
|
|
|
+
|
|
|
+ return base.Apply(animation, control, clock, match, onComplete);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Fallback implementation of <see cref="IBrush"/> animation.
|
|
|
+ /// </summary>
|
|
|
+ public override IBrush? Interpolate(double progress, IBrush? oldValue, IBrush? newValue) => progress >= 0.5 ? newValue : oldValue;
|
|
|
|
|
|
- if (_targetAnimator != null)
|
|
|
+ private bool TryCreateGradientAnimator([NotNullWhen(true)] out IAnimator? animator)
|
|
|
+ {
|
|
|
+ IGradientBrush? firstGradient = null;
|
|
|
+ foreach (var keyframe in this)
|
|
|
{
|
|
|
- foreach (var keyframe in this)
|
|
|
+ if (keyframe.Value is IGradientBrush gradientBrush)
|
|
|
{
|
|
|
- _targetAnimator.Add(keyframe);
|
|
|
+ firstGradient = gradientBrush;
|
|
|
+ break;
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ if (firstGradient is null)
|
|
|
+ {
|
|
|
+ animator = null;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- _targetAnimator.Property = this.Property;
|
|
|
+ var gradientAnimator = new IGradientBrushAnimator();
|
|
|
+ gradientAnimator.Property = Property;
|
|
|
|
|
|
- return _targetAnimator.Apply(animation, control, clock, match, onComplete);
|
|
|
+ foreach (var keyframe in this)
|
|
|
+ {
|
|
|
+ if (keyframe.Value is ISolidColorBrush solidColorBrush)
|
|
|
+ {
|
|
|
+ gradientAnimator.Add(new AnimatorKeyFrame(typeof(IGradientBrushAnimator), keyframe.Cue, keyframe.KeySpline)
|
|
|
+ {
|
|
|
+ Value = IGradientBrushAnimator.ConvertSolidColorBrushToGradient(firstGradient, solidColorBrush)
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (keyframe.Value is IGradientBrush)
|
|
|
+ {
|
|
|
+ gradientAnimator.Add(new AnimatorKeyFrame(typeof(IGradientBrushAnimator), keyframe.Cue, keyframe.KeySpline)
|
|
|
+ {
|
|
|
+ Value = keyframe.Value
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ animator = null;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- Logger.TryGet(LogEventLevel.Error, LogArea.Animations)?.Log(
|
|
|
- this,
|
|
|
- "The animation's keyframe values didn't match any brush animators registered in BaseBrushAnimator.");
|
|
|
-
|
|
|
- return Disposable.Empty;
|
|
|
+ animator = gradientAnimator;
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
- /// <inheritdoc/>
|
|
|
- public override IBrush? Interpolate(double progress, IBrush? oldValue, IBrush? newValue) => null;
|
|
|
+ private bool TryCreateSolidColorBrushAnimator([NotNullWhen(true)] out IAnimator? animator)
|
|
|
+ {
|
|
|
+ var solidColorBrushAnimator = new ISolidColorBrushAnimator();
|
|
|
+ solidColorBrushAnimator.Property = Property;
|
|
|
+
|
|
|
+ foreach (var keyframe in this)
|
|
|
+ {
|
|
|
+ if (keyframe.Value is ISolidColorBrush)
|
|
|
+ {
|
|
|
+ solidColorBrushAnimator.Add(new AnimatorKeyFrame(typeof(ISolidColorBrushAnimator), keyframe.Cue, keyframe.KeySpline)
|
|
|
+ {
|
|
|
+ Value = keyframe.Value
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ animator = null;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- internal static IAnimator? CreateAnimatorFromType(Type type)
|
|
|
+ animator = solidColorBrushAnimator;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool TryCreateCustomRegisteredAnimator([NotNullWhen(true)] out IAnimator? animator)
|
|
|
{
|
|
|
- foreach (var (match, animatorType) in _brushAnimators)
|
|
|
+ if (_brushAnimators.Count > 0)
|
|
|
{
|
|
|
- if (!match(type))
|
|
|
- continue;
|
|
|
+ var firstKeyType = this[0].Value.GetType();
|
|
|
+ foreach (var (match, animatorType) in _brushAnimators)
|
|
|
+ {
|
|
|
+ if (!match(firstKeyType))
|
|
|
+ continue;
|
|
|
|
|
|
- return (IAnimator)Activator.CreateInstance(animatorType);
|
|
|
+ animator = (IAnimator)Activator.CreateInstance(animatorType);
|
|
|
+ if (animator != null)
|
|
|
+ {
|
|
|
+ animator.Property = Property;
|
|
|
+ foreach (var keyframe in this)
|
|
|
+ {
|
|
|
+ animator.Add(new AnimatorKeyFrame(animatorType, keyframe.Cue, keyframe.KeySpline)
|
|
|
+ {
|
|
|
+ Value = keyframe.Value
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- return null;
|
|
|
+ animator = null;
|
|
|
+ return false;
|
|
|
}
|
|
|
}
|
|
|
}
|