diff --git a/samples/RenderTest/Pages/AnimationsPage.xaml b/samples/RenderTest/Pages/AnimationsPage.xaml index c57f0764f9..1dc924145a 100644 --- a/samples/RenderTest/Pages/AnimationsPage.xaml +++ b/samples/RenderTest/Pages/AnimationsPage.xaml @@ -40,81 +40,25 @@ - - - - - + diff --git a/samples/RenderTest/Pages/ClippingPage.xaml b/samples/RenderTest/Pages/ClippingPage.xaml index 879da34615..a47d3e1bd2 100644 --- a/samples/RenderTest/Pages/ClippingPage.xaml +++ b/samples/RenderTest/Pages/ClippingPage.xaml @@ -7,14 +7,14 @@ diff --git a/src/Avalonia.Animation/Animation.cs b/src/Avalonia.Animation/Animation.cs index 98c4961681..c91430c979 100644 --- a/src/Avalonia.Animation/Animation.cs +++ b/src/Avalonia.Animation/Animation.cs @@ -8,14 +8,18 @@ using Avalonia.Metadata; using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.Reflection; +using System.Linq; namespace Avalonia.Animation { /// /// Tracks the progress of an animation. /// - public class Animation : IDisposable, IAnimation + public class Animation : AvaloniaList, IDisposable, IAnimation { + + private bool _isChildrenChanged = false; private List _subscription = new List(); public AvaloniaList _animators { get; set; } = new AvaloniaList(); @@ -54,23 +58,44 @@ namespace Avalonia.Animation /// public Easing Easing { get; set; } = new LinearEasing(); - /// - /// A list of objects. - /// - [Content] - public AvaloniaList Children { get; set; } = new AvaloniaList(); public Animation() { - InterpretKeyframes(); + this.CollectionChanged += delegate { _isChildrenChanged = true; }; + } + + public Animation(IEnumerable items) : base(items) + { + this.CollectionChanged += delegate { _isChildrenChanged = true; }; + } + + public Animation(params KeyFrame[] items) : base(items) + { + this.CollectionChanged += delegate { _isChildrenChanged = true; }; } private void InterpretKeyframes() { - foreach (var keyframe in Children) + var handlerList = new List(); + + foreach (var keyframe in this) { - + foreach (var setter in keyframe) + { + + var custAttr = setter.GetType() + .GetCustomAttributes() + .Where(p => p.GetType() == typeof(AnimatorAttribute)); + + if (!custAttr.Any()) + throw new InvalidProgramException($"Type {setter.GetType()} doesn't have Animator attribute."); + + var match = (AnimatorAttribute)custAttr.First(); + if (!handlerList.Contains(match.HandlerType)) + handlerList.Add(match.HandlerType); + } } + } /// @@ -87,6 +112,12 @@ namespace Avalonia.Animation /// public IDisposable Apply(Animatable control, IObservable matchObs) { + if (_isChildrenChanged) + { + InterpretKeyframes(); + _isChildrenChanged = false; + } + foreach (IAnimator keyframes in _animators) { _subscription.Add(keyframes.Apply(this, control, matchObs)); diff --git a/src/Avalonia.Animation/Animator`1.cs b/src/Avalonia.Animation/Animator`1.cs index 83e32c7739..89da918ec3 100644 --- a/src/Avalonia.Animation/Animator`1.cs +++ b/src/Avalonia.Animation/Animator`1.cs @@ -14,7 +14,7 @@ namespace Avalonia.Animation /// /// Base class for KeyFrames objects /// - public abstract class Animator : AvaloniaList, IAnimator + public abstract class Animator : AvaloniaList, IAnimator { /// /// List of type-converted keyframes. @@ -117,7 +117,7 @@ namespace Avalonia.Animation { var typeConv = TypeDescriptor.GetConverter(type); - foreach (KeyFrame k in this) + foreach (InternalKeyFrame k in this) { if (k.Value == null) { diff --git a/src/Avalonia.Animation/IAnimationSetter.cs b/src/Avalonia.Animation/IAnimationSetter.cs index 28f6f911c4..f2a94c9ed6 100644 --- a/src/Avalonia.Animation/IAnimationSetter.cs +++ b/src/Avalonia.Animation/IAnimationSetter.cs @@ -4,6 +4,5 @@ namespace Avalonia.Animation { AvaloniaProperty Property { get; set; } object Value { get; set; } - } } \ No newline at end of file diff --git a/src/Avalonia.Animation/KeyFrame.cs b/src/Avalonia.Animation/KeyFrame.cs index 07af6b406c..3ffd38e9b4 100644 --- a/src/Avalonia.Animation/KeyFrame.cs +++ b/src/Avalonia.Animation/KeyFrame.cs @@ -12,12 +12,24 @@ namespace Avalonia.Animation /// Stores data regarding a specific key /// point and value in an animation. /// - public class KeyFrame + public class KeyFrame : AvaloniaList { internal bool timeSpanSet, cueSet; private TimeSpan _ktimeSpan; private Cue _kCue; + public KeyFrame() + { + } + + public KeyFrame(IEnumerable items) : base(items) + { + } + + public KeyFrame(params IAnimationSetter[] items) : base(items) + { + } + /// /// Gets or sets the key time of this . /// @@ -60,13 +72,15 @@ namespace Avalonia.Animation } } - /// - /// The keyframe's target value. - /// - public object Value { get; set; } - [Content] - public AvaloniaList Children { get; set; } = new AvaloniaList(); + } + public class InternalKeyFrame + { + public Cue Cue { get; set; } + public TimeSpan KeyTime { get; set; } + internal bool timeSpanSet, cueSet; + public object Value { get; set; } } + } diff --git a/src/Avalonia.Visuals/Animation/TransformAnimator.cs b/src/Avalonia.Visuals/Animation/TransformAnimator.cs index 9f2138225f..7c3966ce93 100644 --- a/src/Avalonia.Visuals/Animation/TransformAnimator.cs +++ b/src/Avalonia.Visuals/Animation/TransformAnimator.cs @@ -84,7 +84,7 @@ namespace Avalonia.Animation { childKeyFrames = new DoubleAnimator(); - foreach (KeyFrame keyframe in this) + foreach (InternalKeyFrame keyframe in this) { childKeyFrames.Add(keyframe); } diff --git a/src/Avalonia.Visuals/Animation/TransformSetter.cs b/src/Avalonia.Visuals/Animation/TransformSetter.cs new file mode 100644 index 0000000000..f8b8d588fc --- /dev/null +++ b/src/Avalonia.Visuals/Animation/TransformSetter.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Linq; +using System.Reactive.Linq; +using System.Diagnostics; +using Avalonia.Animation.Utils; +using Avalonia.Data; + +namespace Avalonia.Animation +{ + [Animator(typeof(TransformAnimator))] + public class TransformSetter : Setter + { + + } +}