diff --git a/src/Avalonia.Animation/Animation.cs b/src/Avalonia.Animation/Animation.cs
index 8b5e760455..c79ee7b8a8 100644
--- a/src/Avalonia.Animation/Animation.cs
+++ b/src/Avalonia.Animation/Animation.cs
@@ -9,14 +9,21 @@ using System.Reactive.Linq;
using System.Threading.Tasks;
using Avalonia.Animation.Easings;
using Avalonia.Collections;
+using Avalonia.Metadata;
namespace Avalonia.Animation
{
///
/// Tracks the progress of an animation.
///
- public class Animation : AvaloniaList, IAnimation
+ public class Animation : AvaloniaObject, IAnimation
{
+ ///
+ /// Gets the children of the .
+ ///
+ [Content]
+ public KeyFrames Children { get; } = new KeyFrames();
+
///
/// Gets or sets the active time of this animation.
///
@@ -42,10 +49,6 @@ namespace Avalonia.Animation
///
public Easing Easing { get; set; } = new LinearEasing();
- ///
- /// Gets or sets the speed multiple for this animation.
- ///
- public double SpeedRatio { get; set; } = 1d;
///
/// Gets or sets the delay time for this animation.
@@ -61,6 +64,24 @@ namespace Avalonia.Animation
///
public TimeSpan DelayBetweenIterations { get; set; } = TimeSpan.Zero;
+ public static readonly DirectProperty SpeedRatioProperty =
+ AvaloniaProperty.RegisterDirect(
+ nameof(_speedRatio),
+ o => o._speedRatio,
+ (o, v) => o._speedRatio = v,
+ 1d);
+
+ private double _speedRatio = 1d;
+
+ ///
+ /// Gets or sets the speed multiple for this animation.
+ ///
+ public double SpeedRatio
+ {
+ get { return _speedRatio; }
+ set { SetAndRaise(SpeedRatioProperty, ref _speedRatio, value); }
+ }
+
private readonly static List<(Func Condition, Type Animator)> Animators = new List<(Func, Type)>
{
( prop => typeof(double).IsAssignableFrom(prop.PropertyType), typeof(DoubleAnimator) )
@@ -90,7 +111,7 @@ namespace Avalonia.Animation
var animatorKeyFrames = new List();
var subscriptions = new List();
- foreach (var keyframe in this)
+ foreach (var keyframe in Children)
{
foreach (var setter in keyframe)
{
diff --git a/src/Avalonia.Animation/AnimationInstance`1.cs b/src/Avalonia.Animation/AnimationInstance`1.cs
index b27be609a5..b793dde8f9 100644
--- a/src/Avalonia.Animation/AnimationInstance`1.cs
+++ b/src/Avalonia.Animation/AnimationInstance`1.cs
@@ -30,7 +30,7 @@ namespace Avalonia.Animation
private Easings.Easing _easeFunc;
private Action _onCompleteAction;
private Func _interpolator;
- private IDisposable _timerSubscription;
+ private IDisposable _timerSub, _speedRatioSub;
private readonly IClock _baseClock;
private IClock _clock;
@@ -47,7 +47,8 @@ namespace Avalonia.Animation
_targetControl = control;
_neutralValue = (T)_targetControl.GetValue(_parent.Property);
- _speedRatio = animation.SpeedRatio;
+ _speedRatioSub = animation.GetObservable(Animation.SpeedRatioProperty)
+ .Subscribe(p => _speedRatio = p);
_initialDelay = animation.Delay;
_duration = animation.Duration;
@@ -57,7 +58,7 @@ namespace Avalonia.Animation
{
case RepeatType.None:
_iterationCount = 1;
- break;
+ break;
case RepeatType.Repeat:
_iterationCount = animation.RepeatCount.Value;
break;
@@ -75,14 +76,15 @@ namespace Avalonia.Animation
// Animation may have been stopped before it has finished.
ApplyFinalFill();
- _timerSubscription?.Dispose();
+ _timerSub?.Dispose();
+ _speedRatioSub?.Dispose();
_clock.PlayState = PlayState.Stop;
}
protected override void Subscribed()
{
_clock = new Clock(_baseClock);
- _timerSubscription = _clock.Subscribe(Step);
+ _timerSub = _clock.Subscribe(Step);
}
public void Step(TimeSpan frameTick)
@@ -134,7 +136,7 @@ namespace Avalonia.Animation
private void InternalStep(TimeSpan time)
{
DoPlayStates();
-
+
// Scale timebases according to speedratio.
var indexTime = time.Ticks;
var iterDuration = _duration.Ticks * _speedRatio;
@@ -153,7 +155,7 @@ namespace Avalonia.Animation
var playbackTime = opsTime % iterationTime;
_currentIteration = (ulong)(opsTime / iterationTime);
-
+
// Stop animation when the current iteration is beyond the iteration count.
if ((_currentIteration + 1) > _iterationCount)
DoComplete();
@@ -178,7 +180,7 @@ namespace Avalonia.Animation
PublishNext(_lastInterpValue);
}
else if (playbackTime > iterDuration &
- playbackTime <= iterationTime &
+ playbackTime <= iterationTime &
iterDelay > 0 &
// The last iteration's trailing delay should be skipped.
(_currentIteration + 1) < _iterationCount)
diff --git a/src/Avalonia.Animation/KeyFrames.cs b/src/Avalonia.Animation/KeyFrames.cs
new file mode 100644
index 0000000000..9e3b1d9f51
--- /dev/null
+++ b/src/Avalonia.Animation/KeyFrames.cs
@@ -0,0 +1,33 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using Avalonia.Collections;
+
+namespace Avalonia.Animation
+{
+ ///
+ /// A collection of s.
+ ///
+ public class KeyFrames : AvaloniaList
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public KeyFrames()
+ {
+ ResetBehavior = ResetBehavior.Remove;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The initial items in the collection.
+ public KeyFrames(IEnumerable items)
+ : base(items)
+ {
+ ResetBehavior = ResetBehavior.Remove;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Visuals/Animation/CrossFade.cs b/src/Avalonia.Visuals/Animation/CrossFade.cs
index d5ddf1c7f5..b07123e050 100644
--- a/src/Avalonia.Visuals/Animation/CrossFade.cs
+++ b/src/Avalonia.Visuals/Animation/CrossFade.cs
@@ -21,7 +21,7 @@ namespace Avalonia.Animation
/// Initializes a new instance of the class.
///
public CrossFade()
- :this(TimeSpan.Zero)
+ : this(TimeSpan.Zero)
{
}
@@ -33,30 +33,36 @@ namespace Avalonia.Animation
{
_fadeOutAnimation = new Animation
{
- new KeyFrame
- (
- new Setter
+ Children =
+ {
+ new KeyFrame
+ (
+ new Setter
+ {
+ Property = Visual.OpacityProperty,
+ Value = 0d
+ }
+ )
{
- Property = Visual.OpacityProperty,
- Value = 0d
+ Cue = new Cue(1d)
}
- )
- {
- Cue = new Cue(1d)
}
};
_fadeInAnimation = new Animation
{
- new KeyFrame
- (
- new Setter
+ Children =
+ {
+ new KeyFrame
+ (
+ new Setter
+ {
+ Property = Visual.OpacityProperty,
+ Value = 0d
+ }
+ )
{
- Property = Visual.OpacityProperty,
- Value = 0d
+ Cue = new Cue(0d)
}
- )
- {
- Cue = new Cue(0d)
}
};
_fadeOutAnimation.Duration = _fadeInAnimation.Duration = duration;
diff --git a/src/Avalonia.Visuals/Animation/PageSlide.cs b/src/Avalonia.Visuals/Animation/PageSlide.cs
index c5d43068c1..c1848d7daa 100644
--- a/src/Avalonia.Visuals/Animation/PageSlide.cs
+++ b/src/Avalonia.Visuals/Animation/PageSlide.cs
@@ -74,34 +74,34 @@ namespace Avalonia.Animation
var distance = Orientation == SlideAxis.Horizontal ? parent.Bounds.Width : parent.Bounds.Height;
var translateProperty = Orientation == SlideAxis.Horizontal ? TranslateTransform.XProperty : TranslateTransform.YProperty;
-
- // TODO: Implement relevant transition logic here (or discard this class)
- // in favor of XAML based transition for pages
if (from != null)
{
var animation = new Animation
{
- new KeyFrame
- (
- new Setter
- {
- Property = translateProperty,
- Value = 0d
- }
- )
+ Children =
{
- Cue = new Cue(0d)
- },
- new KeyFrame
- (
- new Setter
+ new KeyFrame
+ (
+ new Setter
+ {
+ Property = translateProperty,
+ Value = 0d
+ }
+ )
{
- Property = translateProperty,
- Value = forward ? -distance : distance
+ Cue = new Cue(0d)
+ },
+ new KeyFrame
+ (
+ new Setter
+ {
+ Property = translateProperty,
+ Value = forward ? -distance : distance
+ }
+ )
+ {
+ Cue = new Cue(1d)
}
- )
- {
- Cue = new Cue(1d)
}
};
animation.Duration = Duration;
@@ -113,29 +113,31 @@ namespace Avalonia.Animation
to.IsVisible = true;
var animation = new Animation
{
-
- new KeyFrame
- (
- new Setter
- {
- Property = translateProperty,
- Value = forward ? distance : -distance
- }
- )
+ Children =
{
- Cue = new Cue(0d)
- },
- new KeyFrame
- (
- new Setter
+ new KeyFrame
+ (
+ new Setter
+ {
+ Property = translateProperty,
+ Value = forward ? distance : -distance
+ }
+ )
{
- Property = translateProperty,
- Value = 0d
- }
- )
- {
- Cue = new Cue(1d)
- },
+ Cue = new Cue(0d)
+ },
+ new KeyFrame
+ (
+ new Setter
+ {
+ Property = translateProperty,
+ Value = 0d
+ }
+ )
+ {
+ Cue = new Cue(1d)
+ },
+ }
};
animation.Duration = Duration;
tasks.Add(animation.RunAsync(to));