diff --git a/src/Avalonia.Animation/Animation.cs b/src/Avalonia.Animation/Animation.cs
index 05142532e9..c42153ec4f 100644
--- a/src/Avalonia.Animation/Animation.cs
+++ b/src/Avalonia.Animation/Animation.cs
@@ -209,6 +209,17 @@ namespace Avalonia.Animation
( prop => typeof(decimal).IsAssignableFrom(prop.PropertyType), typeof(DecimalAnimator) ),
};
+ ///
+ /// Registers a that can handle
+ /// a value type that matches the specified condition.
+ ///
+ ///
+ /// The condition to which the
+ /// is to be activated and used.
+ ///
+ ///
+ /// The type of the animator to instantiate.
+ ///
public static void RegisterAnimator(Func condition)
where TAnimator : IAnimator
{
diff --git a/src/Avalonia.Visuals/Animation/Animators/BaseBrushAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/BaseBrushAnimator.cs
new file mode 100644
index 0000000000..9576803692
--- /dev/null
+++ b/src/Avalonia.Visuals/Animation/Animators/BaseBrushAnimator.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reactive.Disposables;
+using Avalonia.Logging;
+using Avalonia.Media;
+
+namespace Avalonia.Animation.Animators
+{
+ ///
+ /// Animator that handles all animations on properties
+ /// with as their type and
+ /// redirect them to the properly registered
+ /// animators in this class.
+ ///
+ public class BaseBrushAnimator : Animator
+ {
+ private IAnimator _targetAnimator;
+
+ private static readonly List<(Func Match, Type AnimatorType)> _brushAnimators = new();
+
+ ///
+ /// Register an that handles a specific
+ /// 's descendant value type.
+ ///
+ ///
+ /// The condition to which the
+ /// is to be activated and used.
+ ///
+ ///
+ /// The type of the animator to instantiate.
+ ///
+ public static void RegisterBrushAnimator(Func condition)
+ where TAnimator : IAnimator
+ {
+ _brushAnimators.Insert(0, (condition, typeof(TAnimator)));
+ }
+
+ ///
+ public override IDisposable Apply(Animation animation, Animatable control, IClock clock,
+ IObservable match, Action onComplete)
+ {
+ foreach (var valueType in _brushAnimators
+ .Where(valueType => valueType.Match(this[0].Value.GetType())))
+ {
+ _targetAnimator = (IAnimator)Activator.CreateInstance(valueType.AnimatorType);
+
+ foreach (var keyframe in this)
+ {
+ _targetAnimator.Add(keyframe);
+ }
+
+ _targetAnimator.Property = this.Property;
+
+ _targetAnimator.Apply(animation, control, clock, match, onComplete);
+ }
+
+ 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;
+ }
+
+ ///
+ public override IBrush Interpolate(double progress, IBrush oldValue, IBrush newValue) => null;
+ }
+}
diff --git a/src/Avalonia.Visuals/Animation/Animators/SolidColorBrushAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/SolidColorBrushAnimator.cs
index 3ae9b3be5f..9077ef2e6c 100644
--- a/src/Avalonia.Visuals/Animation/Animators/SolidColorBrushAnimator.cs
+++ b/src/Avalonia.Visuals/Animation/Animators/SolidColorBrushAnimator.cs
@@ -1,21 +1,19 @@
-using System;
-using System.Reactive.Disposables;
-using Avalonia.Media;
+using Avalonia.Media;
using Avalonia.Media.Immutable;
namespace Avalonia.Animation.Animators
{
///
- /// Animator that handles .
+ /// Animator that handles values.
///
public class SolidColorBrushAnimator : Animator
{
public override IBrush Interpolate(double progress, IBrush oldValue, IBrush newValue)
{
- if (!(oldValue is ISolidColorBrush oldValS) || !(newValue is ISolidColorBrush newValS))
+ if (!(oldValue is ISolidColorBrush oldSCB) || !(newValue is ISolidColorBrush newSCB))
return Brushes.Transparent;
-
- return new ImmutableSolidColorBrush(ColorAnimator.InterpolateCore(progress, oldValS.Color, newValS.Color));
+
+ return new ImmutableSolidColorBrush(ColorAnimator.InterpolateCore(progress, oldSCB.Color, newSCB.Color));
}
}
}
diff --git a/src/Avalonia.Visuals/Media/Brush.cs b/src/Avalonia.Visuals/Media/Brush.cs
index a19d5af8b7..fb03d19a4e 100644
--- a/src/Avalonia.Visuals/Media/Brush.cs
+++ b/src/Avalonia.Visuals/Media/Brush.cs
@@ -1,6 +1,7 @@
using System;
using System.ComponentModel;
using Avalonia.Animation;
+using Avalonia.Animation.Animators;
namespace Avalonia.Media
{
@@ -21,6 +22,7 @@ namespace Avalonia.Media
static Brush()
{
+ Animation.Animation.RegisterAnimator(prop => typeof(IBrush).IsAssignableFrom(prop.PropertyType));
AffectsRender(OpacityProperty);
}
diff --git a/src/Avalonia.Visuals/Media/SolidColorBrush.cs b/src/Avalonia.Visuals/Media/SolidColorBrush.cs
index f390489ed5..32663bb8eb 100644
--- a/src/Avalonia.Visuals/Media/SolidColorBrush.cs
+++ b/src/Avalonia.Visuals/Media/SolidColorBrush.cs
@@ -1,4 +1,3 @@
-using Avalonia.Animation;
using Avalonia.Animation.Animators;
using Avalonia.Media.Immutable;
@@ -17,8 +16,8 @@ namespace Avalonia.Media
static SolidColorBrush()
{
- Animation.Animation.RegisterAnimator(prop => typeof(ISolidColorBrush).IsAssignableFrom(prop.PropertyType));
- AffectsRender(ColorProperty);
+ BaseBrushAnimator.RegisterBrushAnimator(match => typeof(ISolidColorBrush).IsAssignableFrom(match));
+ AffectsRender(ColorProperty);
}
///