Browse Source

Make SpeedRatio bindable.

pull/2163/head
Jumar Macato 7 years ago
parent
commit
a941eaeb4e
No known key found for this signature in database GPG Key ID: B19884DAC3A5BF3F
  1. 33
      src/Avalonia.Animation/Animation.cs
  2. 18
      src/Avalonia.Animation/AnimationInstance`1.cs
  3. 33
      src/Avalonia.Animation/KeyFrames.cs
  4. 40
      src/Avalonia.Visuals/Animation/CrossFade.cs
  5. 86
      src/Avalonia.Visuals/Animation/PageSlide.cs

33
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
{
/// <summary>
/// Tracks the progress of an animation.
/// </summary>
public class Animation : AvaloniaList<KeyFrame>, IAnimation
public class Animation : AvaloniaObject, IAnimation
{
/// <summary>
/// Gets the children of the <see cref="Animation"/>.
/// </summary>
[Content]
public KeyFrames Children { get; } = new KeyFrames();
/// <summary>
/// Gets or sets the active time of this animation.
/// </summary>
@ -42,10 +49,6 @@ namespace Avalonia.Animation
/// </summary>
public Easing Easing { get; set; } = new LinearEasing();
/// <summary>
/// Gets or sets the speed multiple for this animation.
/// </summary>
public double SpeedRatio { get; set; } = 1d;
/// <summary>
/// Gets or sets the delay time for this animation.
@ -61,6 +64,24 @@ namespace Avalonia.Animation
/// </summary>
public TimeSpan DelayBetweenIterations { get; set; } = TimeSpan.Zero;
public static readonly DirectProperty<Animation, double> SpeedRatioProperty =
AvaloniaProperty.RegisterDirect<Animation, double>(
nameof(_speedRatio),
o => o._speedRatio,
(o, v) => o._speedRatio = v,
1d);
private double _speedRatio = 1d;
/// <summary>
/// Gets or sets the speed multiple for this animation.
/// </summary>
public double SpeedRatio
{
get { return _speedRatio; }
set { SetAndRaise(SpeedRatioProperty, ref _speedRatio, value); }
}
private readonly static List<(Func<AvaloniaProperty, bool> Condition, Type Animator)> Animators = new List<(Func<AvaloniaProperty, bool>, Type)>
{
( prop => typeof(double).IsAssignableFrom(prop.PropertyType), typeof(DoubleAnimator) )
@ -90,7 +111,7 @@ namespace Avalonia.Animation
var animatorKeyFrames = new List<AnimatorKeyFrame>();
var subscriptions = new List<IDisposable>();
foreach (var keyframe in this)
foreach (var keyframe in Children)
{
foreach (var setter in keyframe)
{

18
src/Avalonia.Animation/AnimationInstance`1.cs

@ -30,7 +30,7 @@ namespace Avalonia.Animation
private Easings.Easing _easeFunc;
private Action _onCompleteAction;
private Func<double, T, T> _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)

33
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
{
/// <summary>
/// A collection of <see cref="KeyFrame"/>s.
/// </summary>
public class KeyFrames : AvaloniaList<KeyFrame>
{
/// <summary>
/// Initializes a new instance of the <see cref="KeyFrames"/> class.
/// </summary>
public KeyFrames()
{
ResetBehavior = ResetBehavior.Remove;
}
/// <summary>
/// Initializes a new instance of the <see cref="KeyFrames"/> class.
/// </summary>
/// <param name="items">The initial items in the collection.</param>
public KeyFrames(IEnumerable<KeyFrame> items)
: base(items)
{
ResetBehavior = ResetBehavior.Remove;
}
}
}

40
src/Avalonia.Visuals/Animation/CrossFade.cs

@ -21,7 +21,7 @@ namespace Avalonia.Animation
/// Initializes a new instance of the <see cref="CrossFade"/> class.
/// </summary>
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;

86
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));

Loading…
Cancel
Save