diff --git a/LottieUWP.Sample/MainPage.xaml b/LottieUWP.Sample/MainPage.xaml index b9f1e3f..5a89573 100644 --- a/LottieUWP.Sample/MainPage.xaml +++ b/LottieUWP.Sample/MainPage.xaml @@ -34,7 +34,7 @@ - + diff --git a/LottieUWP/LottieAnimationView.cs b/LottieUWP/LottieAnimationView.cs index 08e60e0..727cd6a 100644 --- a/LottieUWP/LottieAnimationView.cs +++ b/LottieUWP/LottieAnimationView.cs @@ -550,6 +550,7 @@ public virtual LottieComposition Composition ImageDrawable = _lottieDrawable; _composition = value; + FrameRate = _composition.FrameRate; InvalidateArrange(); InvalidateMeasure(); @@ -769,20 +770,20 @@ private static void RepeatCountPropertyChangedCallback(DependencyObject dependen lottieAnimationView._lottieDrawable.RepeatCount = (int)e.NewValue; } - public int TargetFps + public float FrameRate { - get { return (int)GetValue(TargetFpsProperty); } - set { SetValue(TargetFpsProperty, value); } + get { return (float)GetValue(FrameRateProperty); } + set { SetValue(FrameRateProperty, value); } } // Using a DependencyProperty as the backing store for RepeatCount. This enables animation, styling, binding, etc... - public static readonly DependencyProperty TargetFpsProperty = - DependencyProperty.Register("TargetFps", typeof(int), typeof(LottieAnimationView), new PropertyMetadata(60, TargetFpsPropertyChangedCallback)); + public static readonly DependencyProperty FrameRateProperty = + DependencyProperty.Register("FrameRate", typeof(float), typeof(LottieAnimationView), new PropertyMetadata(60f, FrameRatePropertyChangedCallback)); - private static void TargetFpsPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) + private static void FrameRatePropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { if (dependencyObject is LottieAnimationView lottieAnimationView) - lottieAnimationView._lottieDrawable.TargetFps = (int)e.NewValue; + lottieAnimationView._lottieDrawable.FrameRate = (float)e.NewValue; } public virtual bool IsAnimating => _lottieDrawable.IsAnimating; diff --git a/LottieUWP/LottieDrawable.cs b/LottieUWP/LottieDrawable.cs index 642e7b2..fc62fbe 100644 --- a/LottieUWP/LottieDrawable.cs +++ b/LottieUWP/LottieDrawable.cs @@ -598,10 +598,10 @@ public int RepeatCount get => _animator.RepeatCount; } - public int TargetFps + public float FrameRate { - get => _animator.TargetFps; - set => _animator.TargetFps = value; + get => _animator.FrameRate; + set => _animator.FrameRate = value; } public virtual bool IsAnimating => _animator.IsRunning; diff --git a/LottieUWP/Utils/LottieValueAnimator.cs b/LottieUWP/Utils/LottieValueAnimator.cs index 7287ea3..216669b 100644 --- a/LottieUWP/Utils/LottieValueAnimator.cs +++ b/LottieUWP/Utils/LottieValueAnimator.cs @@ -16,8 +16,9 @@ public class LottieValueAnimator : BaseLottieAnimator private float _minFrame = int.MinValue; private float _maxFrame = int.MaxValue; private LottieComposition _composition; + private float _frameRate; protected bool _isRunning; - + /// /// Returns a float representing the current value of the animation from 0 to 1 /// regardless of the animation speed, direction, or min and max frames. @@ -96,15 +97,17 @@ public override void DoFrame() long timeSinceFrame = now - _frameTime; float frameDuration = FrameDurationNs; float frames = timeSinceFrame / frameDuration; - if (frames == 0) + int wholeFrames = (int)frames; + if (wholeFrames == 0) { return; } - _frame += IsReversed ? -frames : frames; + _frame += IsReversed ? -wholeFrames : wholeFrames; bool ended = !MiscUtils.Contains(_frame, MinFrame, MaxFrame); _frame = MiscUtils.Clamp(_frame, MinFrame, MaxFrame); - _frameTime = now; + float partialFramesDuration = (frames - wholeFrames) * frameDuration; + _frameTime = (long)(now - partialFramesDuration); Debug.WriteLineIf(LottieLog.TraceEnabled, $"Tick milliseconds: {timeSinceFrame}", LottieLog.Tag); @@ -148,11 +151,22 @@ private float FrameDurationNs } } + public override float FrameRate + { + get => _frameRate; + set + { + _frameRate = value <= 1000 ? (value > 1 ? value : 1) : 1000; + UpdateTimerInterval(); + } + } + public LottieComposition Composition { set { _composition = value; + FrameRate = _composition.FrameRate; _frame = MinFrame; _frameTime = SystemnanoTime(); } diff --git a/LottieUWP/ValueAnimator.cs b/LottieUWP/ValueAnimator.cs index 8ce4ae7..40f3e6d 100644 --- a/LottieUWP/ValueAnimator.cs +++ b/LottieUWP/ValueAnimator.cs @@ -36,17 +36,8 @@ public void RemoveAllListeners() private IInterpolator _interpolator; private Timer _timer; - private int _targetFps = 60; - public int TargetFps - { - get => _targetFps; - set - { - _targetFps = value <= 1000 ? (value > 1 ? value : 1) : 1000; - _timer?.Change(TimeSpan.Zero, GetTimerInterval()); - } - } + public abstract float FrameRate { get; set; } protected virtual void OnValueChanged() { @@ -85,9 +76,14 @@ protected void PrivateStart() } } + protected void UpdateTimerInterval() + { + _timer?.Change(TimeSpan.Zero, GetTimerInterval()); + } + private TimeSpan GetTimerInterval() { - return TimeSpan.FromTicks((long)Math.Floor((decimal)TimeSpan.TicksPerSecond / TargetFps)); + return TimeSpan.FromTicks((long)Math.Floor(TimeSpan.TicksPerSecond / (decimal)FrameRate)); } protected virtual void RemoveFrameCallback()