committed by
GitHub
8 changed files with 130 additions and 63 deletions
@ -0,0 +1,69 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Reactive.Disposables; |
|||
using Avalonia.Logging; |
|||
using Avalonia.Media; |
|||
|
|||
namespace Avalonia.Animation.Animators |
|||
{ |
|||
/// <summary>
|
|||
/// Animator that handles all animations on properties
|
|||
/// with <see cref="IBrush"/> as their type and
|
|||
/// redirect them to the properly registered
|
|||
/// animators in this class.
|
|||
/// </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)>(); |
|||
|
|||
/// <summary>
|
|||
/// Register an <see cref="Animator{T}"/> that handles a specific
|
|||
/// <see cref="IBrush"/>'s descendant value type.
|
|||
/// </summary>
|
|||
/// <param name="condition">
|
|||
/// The condition to which the <see cref="Animator{T}"/>
|
|||
/// is to be activated and used.
|
|||
/// </param>
|
|||
/// <typeparam name="TAnimator">
|
|||
/// The type of the animator to instantiate.
|
|||
/// </typeparam>
|
|||
public static void RegisterBrushAnimator<TAnimator>(Func<Type, bool> condition) |
|||
where TAnimator : IAnimator |
|||
{ |
|||
_brushAnimators.Insert(0, (condition, typeof(TAnimator))); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override IDisposable Apply(Animation animation, Animatable control, IClock clock, |
|||
IObservable<bool> match, Action onComplete) |
|||
{ |
|||
foreach (var valueType in _brushAnimators) |
|||
{ |
|||
if (!valueType.Match(this[0].Value.GetType())) continue; |
|||
|
|||
_targetAnimator = (IAnimator)Activator.CreateInstance(valueType.AnimatorType); |
|||
|
|||
foreach (var keyframe in this) |
|||
{ |
|||
_targetAnimator.Add(keyframe); |
|||
} |
|||
|
|||
_targetAnimator.Property = this.Property; |
|||
|
|||
return _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; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override IBrush Interpolate(double progress, IBrush oldValue, IBrush newValue) => null; |
|||
} |
|||
} |
|||
@ -1,71 +1,32 @@ |
|||
using System; |
|||
using System.Reactive.Disposables; |
|||
using Avalonia.Data; |
|||
using Avalonia.Media; |
|||
using Avalonia.Media.Immutable; |
|||
|
|||
namespace Avalonia.Animation.Animators |
|||
{ |
|||
/// <summary>
|
|||
/// Animator that handles <see cref="SolidColorBrush"/>.
|
|||
/// Animator that handles <see cref="SolidColorBrush"/> values.
|
|||
/// </summary>
|
|||
public class SolidColorBrushAnimator : Animator<SolidColorBrush> |
|||
public class ISolidColorBrushAnimator : Animator<ISolidColorBrush> |
|||
{ |
|||
private ColorAnimator _colorAnimator; |
|||
|
|||
private void InitializeColorAnimator() |
|||
public override ISolidColorBrush Interpolate(double progress, ISolidColorBrush oldValue, ISolidColorBrush newValue) |
|||
{ |
|||
_colorAnimator = new ColorAnimator(); |
|||
|
|||
foreach (AnimatorKeyFrame keyframe in this) |
|||
{ |
|||
_colorAnimator.Add(keyframe); |
|||
} |
|||
|
|||
_colorAnimator.Property = SolidColorBrush.ColorProperty; |
|||
return new ImmutableSolidColorBrush(ColorAnimator.InterpolateCore(progress, oldValue.Color, newValue.Color)); |
|||
} |
|||
|
|||
public override IDisposable Apply(Animation animation, Animatable control, IClock clock, IObservable<bool> match, Action onComplete) |
|||
public override IDisposable BindAnimation(Animatable control, IObservable<ISolidColorBrush> instance) |
|||
{ |
|||
// Preprocess keyframe values to Color if the xaml parser converts them to ISCB.
|
|||
foreach (var keyframe in this) |
|||
{ |
|||
if (keyframe.Value is ISolidColorBrush colorBrush) |
|||
{ |
|||
keyframe.Value = colorBrush.Color; |
|||
} |
|||
else |
|||
{ |
|||
return Disposable.Empty; |
|||
} |
|||
} |
|||
|
|||
SolidColorBrush finalTarget; |
|||
var targetVal = control.GetValue(Property); |
|||
if (targetVal is null) |
|||
{ |
|||
finalTarget = new SolidColorBrush(Colors.Transparent); |
|||
control.SetValue(Property, finalTarget); |
|||
} |
|||
else if (targetVal is ImmutableSolidColorBrush immutableSolidColorBrush) |
|||
{ |
|||
finalTarget = new SolidColorBrush(immutableSolidColorBrush.Color); |
|||
control.SetValue(Property, finalTarget); |
|||
} |
|||
else if (targetVal is ISolidColorBrush) |
|||
{ |
|||
finalTarget = targetVal as SolidColorBrush; |
|||
} |
|||
else |
|||
{ |
|||
return Disposable.Empty; |
|||
} |
|||
|
|||
if (_colorAnimator == null) |
|||
InitializeColorAnimator(); |
|||
|
|||
return _colorAnimator.Apply(animation, finalTarget, clock ?? control.Clock, match, onComplete); |
|||
return control.Bind((AvaloniaProperty<IBrush>)Property, instance, BindingPriority.Animation); |
|||
} |
|||
} |
|||
|
|||
[Obsolete] |
|||
public class SolidColorBrushAnimator : Animator<SolidColorBrush> |
|||
{ |
|||
public override SolidColorBrush Interpolate(double progress, SolidColorBrush oldValue, SolidColorBrush newValue) |
|||
{ |
|||
return new SolidColorBrush(ColorAnimator.InterpolateCore(progress, oldValue.Color, newValue.Color)); |
|||
} |
|||
|
|||
public override SolidColorBrush Interpolate(double p, SolidColorBrush o, SolidColorBrush n) => null; |
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue