Browse Source

Remove reflection usage on animators

pull/8787/head
Steven He 4 years ago
parent
commit
e3e0994189
  1. 60
      src/Avalonia.Base/Animation/Animation.cs
  2. 7
      src/Avalonia.Base/Animation/AnimatorKeyFrame.cs
  3. 4
      src/Avalonia.Base/Animation/Animators/Animator`1.cs
  4. 17
      src/Avalonia.Base/Animation/Animators/BaseBrushAnimator.cs

60
src/Avalonia.Base/Animation/Animation.cs

@ -179,14 +179,14 @@ namespace Avalonia.Animation
public KeyFrames Children { get; } = new KeyFrames(); public KeyFrames Children { get; } = new KeyFrames();
// Store values for the Animator attached properties for IAnimationSetter objects. // Store values for the Animator attached properties for IAnimationSetter objects.
private static readonly Dictionary<IAnimationSetter, Type> s_animators = new Dictionary<IAnimationSetter, Type>(); private static readonly Dictionary<IAnimationSetter, (Type Type, Func<IAnimator> Factory)> s_animators = new();
/// <summary> /// <summary>
/// Gets the value of the Animator attached property for a setter. /// Gets the value of the Animator attached property for a setter.
/// </summary> /// </summary>
/// <param name="setter">The animation setter.</param> /// <param name="setter">The animation setter.</param>
/// <returns>The property animator type.</returns> /// <returns>The property animator type.</returns>
public static Type? GetAnimator(IAnimationSetter setter) public static (Type, Func<IAnimator>)? GetAnimator(IAnimationSetter setter)
{ {
if (s_animators.TryGetValue(setter, out var type)) if (s_animators.TryGetValue(setter, out var type))
{ {
@ -199,25 +199,25 @@ namespace Avalonia.Animation
/// Sets the value of the Animator attached property for a setter. /// Sets the value of the Animator attached property for a setter.
/// </summary> /// </summary>
/// <param name="setter">The animation setter.</param> /// <param name="setter">The animation setter.</param>
/// <param name="value">The property animator value.</param> public static void SetAnimator<TAnimator>(IAnimationSetter setter)
public static void SetAnimator(IAnimationSetter setter, Type value) where TAnimator : IAnimator, new()
{ {
s_animators[setter] = value; s_animators[setter] = (typeof(TAnimator), () => new TAnimator());
} }
private readonly static List<(Func<AvaloniaProperty, bool> Condition, Type Animator)> Animators = new List<(Func<AvaloniaProperty, bool>, Type)> private readonly static List<(Func<AvaloniaProperty, bool> Condition, Type Animator, Func<IAnimator> Factory)> Animators = new()
{ {
( prop => typeof(bool).IsAssignableFrom(prop.PropertyType), typeof(BoolAnimator) ), ( prop => typeof(bool).IsAssignableFrom(prop.PropertyType), typeof(BoolAnimator), () => new BoolAnimator() ),
( prop => typeof(byte).IsAssignableFrom(prop.PropertyType), typeof(ByteAnimator) ), ( prop => typeof(byte).IsAssignableFrom(prop.PropertyType), typeof(ByteAnimator), () => new ByteAnimator() ),
( prop => typeof(Int16).IsAssignableFrom(prop.PropertyType), typeof(Int16Animator) ), ( prop => typeof(Int16).IsAssignableFrom(prop.PropertyType), typeof(Int16Animator), () => new Int16Animator() ),
( prop => typeof(Int32).IsAssignableFrom(prop.PropertyType), typeof(Int32Animator) ), ( prop => typeof(Int32).IsAssignableFrom(prop.PropertyType), typeof(Int32Animator), () => new Int32Animator() ),
( prop => typeof(Int64).IsAssignableFrom(prop.PropertyType), typeof(Int64Animator) ), ( prop => typeof(Int64).IsAssignableFrom(prop.PropertyType), typeof(Int64Animator), () => new Int64Animator() ),
( prop => typeof(UInt16).IsAssignableFrom(prop.PropertyType), typeof(UInt16Animator) ), ( prop => typeof(UInt16).IsAssignableFrom(prop.PropertyType), typeof(UInt16Animator), () => new UInt16Animator() ),
( prop => typeof(UInt32).IsAssignableFrom(prop.PropertyType), typeof(UInt32Animator) ), ( prop => typeof(UInt32).IsAssignableFrom(prop.PropertyType), typeof(UInt32Animator), () => new UInt32Animator() ),
( prop => typeof(UInt64).IsAssignableFrom(prop.PropertyType), typeof(UInt64Animator) ), ( prop => typeof(UInt64).IsAssignableFrom(prop.PropertyType), typeof(UInt64Animator), () => new UInt64Animator() ),
( prop => typeof(float).IsAssignableFrom(prop.PropertyType), typeof(FloatAnimator) ), ( prop => typeof(float).IsAssignableFrom(prop.PropertyType), typeof(FloatAnimator), () => new FloatAnimator() ),
( prop => typeof(double).IsAssignableFrom(prop.PropertyType), typeof(DoubleAnimator) ), ( prop => typeof(double).IsAssignableFrom(prop.PropertyType), typeof(DoubleAnimator), () => new DoubleAnimator() ),
( prop => typeof(decimal).IsAssignableFrom(prop.PropertyType), typeof(DecimalAnimator) ), ( prop => typeof(decimal).IsAssignableFrom(prop.PropertyType), typeof(DecimalAnimator), () => new DecimalAnimator() ),
}; };
/// <summary> /// <summary>
@ -232,18 +232,18 @@ namespace Avalonia.Animation
/// The type of the animator to instantiate. /// The type of the animator to instantiate.
/// </typeparam> /// </typeparam>
public static void RegisterAnimator<TAnimator>(Func<AvaloniaProperty, bool> condition) public static void RegisterAnimator<TAnimator>(Func<AvaloniaProperty, bool> condition)
where TAnimator : IAnimator where TAnimator : IAnimator, new()
{ {
Animators.Insert(0, (condition, typeof(TAnimator))); Animators.Insert(0, (condition, typeof(TAnimator), () => new TAnimator()));
} }
private static Type? GetAnimatorType(AvaloniaProperty property) private static (Type Type, Func<IAnimator> Factory)? GetAnimatorType(AvaloniaProperty property)
{ {
foreach (var (condition, type) in Animators) foreach (var (condition, type, factory) in Animators)
{ {
if (condition(property)) if (condition(property))
{ {
return type; return (type, factory);
} }
} }
return null; return null;
@ -251,7 +251,7 @@ namespace Avalonia.Animation
private (IList<IAnimator> Animators, IList<IDisposable> subscriptions) InterpretKeyframes(Animatable control) private (IList<IAnimator> Animators, IList<IDisposable> subscriptions) InterpretKeyframes(Animatable control)
{ {
var handlerList = new List<(Type type, AvaloniaProperty property)>(); var handlerList = new Dictionary<(Type type, AvaloniaProperty Property), Func<IAnimator>>();
var animatorKeyFrames = new List<AnimatorKeyFrame>(); var animatorKeyFrames = new List<AnimatorKeyFrame>();
var subscriptions = new List<IDisposable>(); var subscriptions = new List<IDisposable>();
@ -271,8 +271,10 @@ namespace Avalonia.Animation
throw new InvalidOperationException($"No animator registered for the property {setter.Property}. Add an animator to the Animation.Animators collection that matches this property to animate it."); throw new InvalidOperationException($"No animator registered for the property {setter.Property}. Add an animator to the Animation.Animators collection that matches this property to animate it.");
} }
if (!handlerList.Contains((handler, setter.Property))) var (type, factory) = handler.Value;
handlerList.Add((handler, setter.Property));
if (!handlerList.ContainsKey((type, setter.Property)))
handlerList[(type, setter.Property)] = factory;
var cue = keyframe.Cue; var cue = keyframe.Cue;
@ -281,7 +283,7 @@ namespace Avalonia.Animation
cue = new Cue(keyframe.KeyTime.TotalSeconds / Duration.TotalSeconds); cue = new Cue(keyframe.KeyTime.TotalSeconds / Duration.TotalSeconds);
} }
var newKF = new AnimatorKeyFrame(handler, cue, keyframe.KeySpline); var newKF = new AnimatorKeyFrame(type, factory, cue, keyframe.KeySpline);
subscriptions.Add(newKF.BindSetter(setter, control)); subscriptions.Add(newKF.BindSetter(setter, control));
@ -291,10 +293,10 @@ namespace Avalonia.Animation
var newAnimatorInstances = new List<IAnimator>(); var newAnimatorInstances = new List<IAnimator>();
foreach (var (handlerType, property) in handlerList) foreach (var handler in handlerList)
{ {
var newInstance = (IAnimator)Activator.CreateInstance(handlerType)!; var newInstance = handler.Value();
newInstance.Property = property; newInstance.Property = handler.Key.Property;
newAnimatorInstances.Add(newInstance); newAnimatorInstances.Add(newInstance);
} }

7
src/Avalonia.Base/Animation/AnimatorKeyFrame.cs

@ -20,22 +20,25 @@ namespace Avalonia.Animation
} }
public AnimatorKeyFrame(Type? animatorType, Cue cue) public AnimatorKeyFrame(Type? animatorType, Func<IAnimator>? animatorFactory, Cue cue)
{ {
AnimatorType = animatorType; AnimatorType = animatorType;
AnimatorFactory = animatorFactory;
Cue = cue; Cue = cue;
KeySpline = null; KeySpline = null;
} }
public AnimatorKeyFrame(Type? animatorType, Cue cue, KeySpline? keySpline) public AnimatorKeyFrame(Type? animatorType, Func<IAnimator>? animatorFactory, Cue cue, KeySpline? keySpline)
{ {
AnimatorType = animatorType; AnimatorType = animatorType;
AnimatorFactory = animatorFactory;
Cue = cue; Cue = cue;
KeySpline = keySpline; KeySpline = keySpline;
} }
internal bool isNeutral; internal bool isNeutral;
public Type? AnimatorType { get; } public Type? AnimatorType { get; }
public Func<IAnimator>? AnimatorFactory { get; }
public Cue Cue { get; } public Cue Cue { get; }
public KeySpline? KeySpline { get; } public KeySpline? KeySpline { get; }
public AvaloniaProperty? Property { get; private set; } public AvaloniaProperty? Property { get; private set; }

4
src/Avalonia.Base/Animation/Animators/Animator`1.cs

@ -171,12 +171,12 @@ namespace Avalonia.Animation.Animators
{ {
if (!hasStartKey) if (!hasStartKey)
{ {
_convertedKeyframes.Insert(0, new AnimatorKeyFrame(null, new Cue(0.0d)) { Value = default(T), isNeutral = true }); _convertedKeyframes.Insert(0, new AnimatorKeyFrame(null, null, new Cue(0.0d)) { Value = default(T), isNeutral = true });
} }
if (!hasEndKey) if (!hasEndKey)
{ {
_convertedKeyframes.Add(new AnimatorKeyFrame(null, new Cue(1.0d)) { Value = default(T), isNeutral = true }); _convertedKeyframes.Add(new AnimatorKeyFrame(null, null, new Cue(1.0d)) { Value = default(T), isNeutral = true });
} }
} }
} }

17
src/Avalonia.Base/Animation/Animators/BaseBrushAnimator.cs

@ -17,8 +17,7 @@ namespace Avalonia.Animation.Animators
/// </summary> /// </summary>
public class BaseBrushAnimator : Animator<IBrush?> public class BaseBrushAnimator : Animator<IBrush?>
{ {
private static readonly List<(Func<Type, bool> Match, Type AnimatorType)> _brushAnimators = private static readonly List<(Func<Type, bool> Match, Type AnimatorType, Func<IAnimator> AnimatorFactory)> _brushAnimators = new();
new List<(Func<Type, bool> Match, Type AnimatorType)>();
/// <summary> /// <summary>
/// Register an <see cref="Animator{T}"/> that handles a specific /// Register an <see cref="Animator{T}"/> that handles a specific
@ -34,7 +33,7 @@ namespace Avalonia.Animation.Animators
public static void RegisterBrushAnimator<TAnimator>(Func<Type, bool> condition) public static void RegisterBrushAnimator<TAnimator>(Func<Type, bool> condition)
where TAnimator : IAnimator, new() where TAnimator : IAnimator, new()
{ {
_brushAnimators.Insert(0, (condition, typeof(TAnimator))); _brushAnimators.Insert(0, (condition, typeof(TAnimator), () => new TAnimator()));
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -85,14 +84,14 @@ namespace Avalonia.Animation.Animators
{ {
if (keyframe.Value is ISolidColorBrush solidColorBrush) if (keyframe.Value is ISolidColorBrush solidColorBrush)
{ {
gradientAnimator.Add(new AnimatorKeyFrame(typeof(GradientBrushAnimator), keyframe.Cue, keyframe.KeySpline) gradientAnimator.Add(new AnimatorKeyFrame(typeof(GradientBrushAnimator), () => new GradientBrushAnimator(), keyframe.Cue, keyframe.KeySpline)
{ {
Value = GradientBrushAnimator.ConvertSolidColorBrushToGradient(firstGradient, solidColorBrush) Value = GradientBrushAnimator.ConvertSolidColorBrushToGradient(firstGradient, solidColorBrush)
}); });
} }
else if (keyframe.Value is IGradientBrush) else if (keyframe.Value is IGradientBrush)
{ {
gradientAnimator.Add(new AnimatorKeyFrame(typeof(GradientBrushAnimator), keyframe.Cue, keyframe.KeySpline) gradientAnimator.Add(new AnimatorKeyFrame(typeof(GradientBrushAnimator), () => new GradientBrushAnimator(), keyframe.Cue, keyframe.KeySpline)
{ {
Value = keyframe.Value Value = keyframe.Value
}); });
@ -117,7 +116,7 @@ namespace Avalonia.Animation.Animators
{ {
if (keyframe.Value is ISolidColorBrush) if (keyframe.Value is ISolidColorBrush)
{ {
solidColorBrushAnimator.Add(new AnimatorKeyFrame(typeof(ISolidColorBrushAnimator), keyframe.Cue, keyframe.KeySpline) solidColorBrushAnimator.Add(new AnimatorKeyFrame(typeof(ISolidColorBrushAnimator), () => new ISolidColorBrushAnimator(), keyframe.Cue, keyframe.KeySpline)
{ {
Value = keyframe.Value Value = keyframe.Value
}); });
@ -137,18 +136,18 @@ namespace Avalonia.Animation.Animators
{ {
if (_brushAnimators.Count > 0 && this[0].Value?.GetType() is Type firstKeyType) if (_brushAnimators.Count > 0 && this[0].Value?.GetType() is Type firstKeyType)
{ {
foreach (var (match, animatorType) in _brushAnimators) foreach (var (match, animatorType, animatorFactory) in _brushAnimators)
{ {
if (!match(firstKeyType)) if (!match(firstKeyType))
continue; continue;
animator = (IAnimator?)Activator.CreateInstance(animatorType); animator = animatorFactory();
if (animator != null) if (animator != null)
{ {
animator.Property = Property; animator.Property = Property;
foreach (var keyframe in this) foreach (var keyframe in this)
{ {
animator.Add(new AnimatorKeyFrame(animatorType, keyframe.Cue, keyframe.KeySpline) animator.Add(new AnimatorKeyFrame(animatorType, animatorFactory, keyframe.Cue, keyframe.KeySpline)
{ {
Value = keyframe.Value Value = keyframe.Value
}); });

Loading…
Cancel
Save