From d8ed9630bda0a22ad60389aaf083e7273917474c Mon Sep 17 00:00:00 2001 From: "E.Z. Hart" Date: Fri, 8 Apr 2016 12:26:03 -0600 Subject: Automatically marshal all AnimationExtensions calls onto UI thread (#48) --- Xamarin.Forms.Core/AnimationExtensions.cs | 155 ++++++++++++++++++------------ 1 file changed, 94 insertions(+), 61 deletions(-) (limited to 'Xamarin.Forms.Core/AnimationExtensions.cs') diff --git a/Xamarin.Forms.Core/AnimationExtensions.cs b/Xamarin.Forms.Core/AnimationExtensions.cs index efc3e405..957d002e 100644 --- a/Xamarin.Forms.Core/AnimationExtensions.cs +++ b/Xamarin.Forms.Core/AnimationExtensions.cs @@ -42,11 +42,29 @@ namespace Xamarin.Forms public static bool AbortAnimation(this IAnimatable self, string handle) { - CheckAccess(); - var key = new AnimatableKey(self, handle); - return AbortAnimation(key) && AbortKinetic(key); + if (!s_animations.ContainsKey(key) && !s_kinetics.ContainsKey(key)) + { + return false; + } + + Action abort = () => + { + AbortAnimation(key); + AbortKinetic(key); + }; + + if (Device.IsInvokeRequired) + { + Device.BeginInvokeOnMainThread(abort); + } + else + { + abort(); + } + + return true; } public static void Animate(this IAnimatable self, string name, Animation animation, uint rate = 16, uint length = 250, Easing easing = null, Action finished = null, @@ -67,8 +85,9 @@ namespace Xamarin.Forms self.Animate(name, x => x, callback, rate, length, easing, finished, repeat); } - public static void Animate(this IAnimatable self, string name, Func transform, Action callback, uint rate = 16, uint length = 250, Easing easing = null, - Action finished = null, Func repeat = null) + public static void Animate(this IAnimatable self, string name, Func transform, Action callback, + uint rate = 16, uint length = 250, Easing easing = null, + Action finished = null, Func repeat = null) { if (transform == null) throw new ArgumentNullException(nameof(transform)); @@ -77,8 +96,75 @@ namespace Xamarin.Forms if (self == null) throw new ArgumentNullException(nameof(self)); - CheckAccess(); + Action animate = () => AnimateInternal(self, name, transform, callback, rate, length, easing, finished, repeat); + + if (Device.IsInvokeRequired) + { + Device.BeginInvokeOnMainThread(animate); + } + else + { + animate(); + } + } + + + public static void AnimateKinetic(this IAnimatable self, string name, Func callback, double velocity, double drag, Action finished = null) + { + Action animate = () => AnimateKineticInternal(self, name, callback, velocity, drag, finished); + + if (Device.IsInvokeRequired) + { + Device.BeginInvokeOnMainThread(animate); + } + else + { + animate(); + } + } + + public static bool AnimationIsRunning(this IAnimatable self, string handle) + { + var key = new AnimatableKey(self, handle); + return s_animations.ContainsKey(key); + } + + public static Func Interpolate(double start, double end = 1.0f, double reverseVal = 0.0f, bool reverse = false) + { + double target = reverse ? reverseVal : end; + return x => start + (target - start) * x; + } + + static void AbortAnimation(AnimatableKey key) + { + if (!s_animations.ContainsKey(key)) + { + return; + } + + Info info = s_animations[key]; + info.Tweener.ValueUpdated -= HandleTweenerUpdated; + info.Tweener.Finished -= HandleTweenerFinished; + info.Tweener.Stop(); + info.Finished?.Invoke(1.0f, true); + + s_animations.Remove(key); + } + static void AbortKinetic(AnimatableKey key) + { + if (!s_kinetics.ContainsKey(key)) + { + return; + } + + Ticker.Default.Remove(s_kinetics[key]); + s_kinetics.Remove(key); + } + + static void AnimateInternal(IAnimatable self, string name, Func transform, Action callback, + uint rate, uint length, Easing easing, Action finished, Func repeat) + { var key = new AnimatableKey(self, name); AbortAnimation(key); @@ -107,10 +193,8 @@ namespace Xamarin.Forms tweener.Start(); } - public static void AnimateKinetic(this IAnimatable self, string name, Func callback, double velocity, double drag, Action finished = null) + static void AnimateKineticInternal(IAnimatable self, string name, Func callback, double velocity, double drag, Action finished = null) { - CheckAccess(); - var key = new AnimatableKey(self, name); AbortKinetic(key); @@ -118,8 +202,7 @@ namespace Xamarin.Forms double sign = velocity / Math.Abs(velocity); velocity = Math.Abs(velocity); - int tick = Ticker.Default.Insert(step => - { + int tick = Ticker.Default.Insert(step => { long ms = step; velocity -= drag * ms; @@ -142,56 +225,6 @@ namespace Xamarin.Forms s_kinetics[key] = tick; } - public static bool AnimationIsRunning(this IAnimatable self, string handle) - { - CheckAccess(); - - var key = new AnimatableKey(self, handle); - - return s_animations.ContainsKey(key); - } - - public static Func Interpolate(double start, double end = 1.0f, double reverseVal = 0.0f, bool reverse = false) - { - double target = reverse ? reverseVal : end; - return x => start + (target - start) * x; - } - - static bool AbortAnimation(AnimatableKey key) - { - if (!s_animations.ContainsKey(key)) - { - return false; - } - - Info info = s_animations[key]; - info.Tweener.ValueUpdated -= HandleTweenerUpdated; - info.Tweener.Finished -= HandleTweenerFinished; - info.Tweener.Stop(); - info.Finished?.Invoke(1.0f, true); - - return s_animations.Remove(key); - } - - static bool AbortKinetic(AnimatableKey key) - { - if (!s_kinetics.ContainsKey(key)) - { - return false; - } - - Ticker.Default.Remove(s_kinetics[key]); - return s_kinetics.Remove(key); - } - - static void CheckAccess() - { - if (Device.IsInvokeRequired) - { - throw new InvalidOperationException("Animation operations must be invoked on the UI thread"); - } - } - static void HandleTweenerFinished(object o, EventArgs args) { var tweener = o as Tweener; -- cgit v1.2.3