From 97dc1e82303147ecbfd320e486f7957b0d076646 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 29 Mar 2019 22:09:47 +0100 Subject: [PATCH 1/5] Added size animation APIs --- .../Abstract/AnimationBuilderBase.cs | 31 ++++++++++++++++ .../Animations/CompositionAnimationBuilder.cs | 37 +++++++++++++++++++ .../Interfaces/IAnimationBuilder.cs | 36 ++++++++++++++++++ .../Animations/XamlAnimationBuilder.cs | 19 +++++++++- 4 files changed, 122 insertions(+), 1 deletion(-) diff --git a/UICompositionAnimations/Animations/Abstract/AnimationBuilderBase.cs b/UICompositionAnimations/Animations/Abstract/AnimationBuilderBase.cs index 2c49970..967e546 100644 --- a/UICompositionAnimations/Animations/Abstract/AnimationBuilderBase.cs +++ b/UICompositionAnimations/Animations/Abstract/AnimationBuilderBase.cs @@ -167,6 +167,37 @@ internal abstract class AnimationBuilderBase : IAnimationBuilder [MustUseReturnValue, NotNull] protected abstract IAnimationBuilder OnClip(Side side, double? from, double to, Easing ease); + /// + public IAnimationBuilder Size(Axis axis, double to, Easing ease = Easing.Linear) => OnSize(axis, null, to, ease); + + /// + public IAnimationBuilder Size(Axis axis, double from, double to, Easing ease = Easing.Linear) => OnSize(axis, from, to, ease); + + /// + /// Schedules a size animation on a single axis + /// + /// The target axis to animate + /// The optional starting value + /// The target value + /// The easing function to use for the size animation + [MustUseReturnValue, NotNull] + protected abstract IAnimationBuilder OnSize(Axis axis, double? from, double to, Easing ease); + + /// + public IAnimationBuilder Size(Vector2 to, Easing ease = Easing.Linear) => OnSize(null, to, ease); + + /// + public IAnimationBuilder Size(Vector2 from, Vector2 to, Easing ease = Easing.Linear) => OnSize(from, to, ease); + + /// + /// Schedules a 2D size animation + /// + /// The optional starting position + /// The target position + /// The easing function to use for the size animation + [MustUseReturnValue, NotNull] + protected abstract IAnimationBuilder OnSize(Vector2? from, Vector2 to, Easing ease = Easing.Linear); + #endregion /// diff --git a/UICompositionAnimations/Animations/CompositionAnimationBuilder.cs b/UICompositionAnimations/Animations/CompositionAnimationBuilder.cs index 375ab5c..0208cb9 100644 --- a/UICompositionAnimations/Animations/CompositionAnimationBuilder.cs +++ b/UICompositionAnimations/Animations/CompositionAnimationBuilder.cs @@ -186,6 +186,43 @@ protected override IAnimationBuilder OnClip(Side side, double? from, double to, return this; } + /// + protected override IAnimationBuilder OnSize(Axis axis, double? from, double to, Easing ease) + { + AnimationFactories.Add(duration => + { + // Stop the animation and get the easing function + string property = $"{nameof(Visual.Size)}.{axis}"; + TargetVisual.StopAnimation(property); + CompositionEasingFunction easingFunction = TargetVisual.GetEasingFunction(ease); + + // Create and return the animation + ScalarKeyFrameAnimation animation = TargetVisual.Compositor.CreateScalarKeyFrameAnimation((float?)from, (float)to, duration, null, easingFunction); + TargetVisual.StartAnimation(property, animation); + }); + + return this; + } + + /// + protected override IAnimationBuilder OnSize(Vector2? from, Vector2 to, Easing ease = Easing.Linear) + { + AnimationFactories.Add(duration => + { + // Stop the animation and get the easing function + TargetVisual.StopAnimation(nameof(Visual.Size)); + CompositionEasingFunction easingFunction = TargetVisual.GetEasingFunction(ease); + + // Create and return the animation + Vector3? from3 = from == null ? default : new Vector3(from.Value, 0); + Vector3 to3 = new Vector3(to, 0); + Vector3KeyFrameAnimation animation = TargetVisual.Compositor.CreateVector3KeyFrameAnimation(from3, to3, duration, null, easingFunction); + TargetVisual.StartAnimation(nameof(Visual.Size), animation); + }); + + return this; + } + /// /// Creates and starts the pending animations /// diff --git a/UICompositionAnimations/Animations/Interfaces/IAnimationBuilder.cs b/UICompositionAnimations/Animations/Interfaces/IAnimationBuilder.cs index 7bf99d4..202cc33 100644 --- a/UICompositionAnimations/Animations/Interfaces/IAnimationBuilder.cs +++ b/UICompositionAnimations/Animations/Interfaces/IAnimationBuilder.cs @@ -154,6 +154,42 @@ public interface IAnimationBuilder [MustUseReturnValue, NotNull] IAnimationBuilder Clip(Side side, double from, double to, Easing ease = Easing.Linear); + /// + /// Schedules a size animation + /// + /// The size axis to animate + /// The target size value to animate to + /// The easing function to use for the size animation + [MustUseReturnValue, NotNull] + IAnimationBuilder Size(Axis axis, double to, Easing ease = Easing.Linear); + + /// + /// Schedules a size animation + /// + /// The size axis to animate + /// The initial size value to animate from + /// The target size value to animate to + /// The easing function to use for the size animation + [MustUseReturnValue, NotNull] + IAnimationBuilder Size(Axis axis, double from, double to, Easing ease = Easing.Linear); + + /// + /// Schedules a size animation + /// + /// The target size position to animate to + /// The easing function to use for the size animation + [MustUseReturnValue, NotNull] + IAnimationBuilder Size(Vector2 to, Easing ease = Easing.Linear); + + /// + /// Schedules a size animation + /// + /// The initial size position to animate from + /// The target size position to animate to + /// The easing function to use for the size animation + [MustUseReturnValue, NotNull] + IAnimationBuilder Size(Vector2 from, Vector2 to, Easing ease = Easing.Linear); + /// /// Sets the duration of the animation /// diff --git a/UICompositionAnimations/Animations/XamlAnimationBuilder.cs b/UICompositionAnimations/Animations/XamlAnimationBuilder.cs index f219ff1..5893794 100644 --- a/UICompositionAnimations/Animations/XamlAnimationBuilder.cs +++ b/UICompositionAnimations/Animations/XamlAnimationBuilder.cs @@ -77,7 +77,24 @@ protected override IAnimationBuilder OnRotate(double? from, double to, Easing ea } /// - protected override IAnimationBuilder OnClip(Side side, double? @from, double to, Easing ease) => throw new NotSupportedException("Can't animate the clip property from XAML"); + protected override IAnimationBuilder OnClip(Side side, double? from, double to, Easing ease) => throw new NotSupportedException("Can't animate the clip property from XAML"); + + /// + protected override IAnimationBuilder OnSize(Axis axis, double? from, double to, Easing ease) + { + AnimationFactories.Add(duration => TargetElement.CreateDoubleAnimation(axis == Axis.X ? nameof(FrameworkElement.Width) : nameof(FrameworkElement.Height), from, to, duration, ease, true)); + + return this; + } + + /// + protected override IAnimationBuilder OnSize(Vector2? from, Vector2 to, Easing ease = Easing.Linear) + { + AnimationFactories.Add(duration => TargetTransform.CreateDoubleAnimation(nameof(FrameworkElement.Width), from?.X, to.X, duration, ease, true)); + AnimationFactories.Add(duration => TargetTransform.CreateDoubleAnimation(nameof(FrameworkElement.Height), from?.Y, to.Y, duration, ease, true)); + + return this; + } /// /// Gets the represented by the current instance From b0f0116c61f4cd43c0248e8f052fc2286e9aac16 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 29 Mar 2019 22:24:53 +0100 Subject: [PATCH 2/5] Fixed XAML size animation with NaN starting value --- .../Animations/XamlAnimationBuilder.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/UICompositionAnimations/Animations/XamlAnimationBuilder.cs b/UICompositionAnimations/Animations/XamlAnimationBuilder.cs index 5893794..1bb9bc9 100644 --- a/UICompositionAnimations/Animations/XamlAnimationBuilder.cs +++ b/UICompositionAnimations/Animations/XamlAnimationBuilder.cs @@ -82,7 +82,16 @@ protected override IAnimationBuilder OnRotate(double? from, double to, Easing ea /// protected override IAnimationBuilder OnSize(Axis axis, double? from, double to, Easing ease) { - AnimationFactories.Add(duration => TargetElement.CreateDoubleAnimation(axis == Axis.X ? nameof(FrameworkElement.Width) : nameof(FrameworkElement.Height), from, to, duration, ease, true)); + if (!(TargetElement is FrameworkElement element)) throw new InvalidOperationException("Can't animate the size of an item that's not a framework element"); + AnimationFactories.Add(duration => + { + switch (axis) + { + case Axis.X: return TargetElement.CreateDoubleAnimation(nameof(FrameworkElement.Width), double.IsNaN(element.Width) ? element.ActualWidth : from, to, duration, ease, true); + case Axis.Y: return TargetElement.CreateDoubleAnimation(nameof(FrameworkElement.Height), double.IsNaN(element.Height) ? element.ActualHeight : from, to, duration, ease, true); + default: throw new ArgumentException($"Invalid axis: {axis}", nameof(axis)); + } + }); return this; } @@ -90,8 +99,12 @@ protected override IAnimationBuilder OnSize(Axis axis, double? from, double to, /// protected override IAnimationBuilder OnSize(Vector2? from, Vector2 to, Easing ease = Easing.Linear) { - AnimationFactories.Add(duration => TargetTransform.CreateDoubleAnimation(nameof(FrameworkElement.Width), from?.X, to.X, duration, ease, true)); - AnimationFactories.Add(duration => TargetTransform.CreateDoubleAnimation(nameof(FrameworkElement.Height), from?.Y, to.Y, duration, ease, true)); + if (!(TargetElement is FrameworkElement element)) throw new InvalidOperationException("Can't animate the size of an item that's not a framework element"); + double? + fromX = double.IsNaN(element.Width) ? (double?)element.ActualWidth : from?.X, + fromY = double.IsNaN(element.Height) ? (double?)element.ActualHeight : from?.Y; + AnimationFactories.Add(duration => TargetTransform.CreateDoubleAnimation(nameof(FrameworkElement.Width), fromX, to.X, duration, ease, true)); + AnimationFactories.Add(duration => TargetTransform.CreateDoubleAnimation(nameof(FrameworkElement.Height), fromY, to.Y, duration, ease, true)); return this; } From 7d99f5b66a0d889f7a4d161189b89f44e2d315a4 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 29 Mar 2019 22:47:13 +0100 Subject: [PATCH 3/5] Code refactoring to the composition animation builder --- .../Animations/CompositionAnimationBuilder.cs | 141 +++++------------- 1 file changed, 34 insertions(+), 107 deletions(-) diff --git a/UICompositionAnimations/Animations/CompositionAnimationBuilder.cs b/UICompositionAnimations/Animations/CompositionAnimationBuilder.cs index 0208cb9..ccba239 100644 --- a/UICompositionAnimations/Animations/CompositionAnimationBuilder.cs +++ b/UICompositionAnimations/Animations/CompositionAnimationBuilder.cs @@ -29,92 +29,19 @@ public CompositionAnimationBuilder([NotNull] UIElement target) : base(target) } /// - protected override IAnimationBuilder OnOpacity(double? from, double to, Easing ease) - { - AnimationFactories.Add(duration => - { - TargetVisual.StopAnimation(nameof(Visual.Opacity)); - CompositionEasingFunction easingFunction = TargetVisual.GetEasingFunction(ease); - ScalarKeyFrameAnimation animation = TargetVisual.Compositor.CreateScalarKeyFrameAnimation((float?)from, (float)to, duration, null, easingFunction); - TargetVisual.StartAnimation(nameof(Visual.Opacity), animation); - }); - - return this; - } + protected override IAnimationBuilder OnOpacity(double? from, double to, Easing ease) => OnScalarAnimation(nameof(Visual.Opacity), from, to, ease); /// - protected override IAnimationBuilder OnTranslation(Axis axis, double? from, double to, Easing ease) - { - AnimationFactories.Add(duration => - { - // Stop the animation and get the easing function - string property = $"Translation.{axis}"; - TargetVisual.StopAnimation(property); - CompositionEasingFunction easingFunction = TargetVisual.GetEasingFunction(ease); - - // Create and return the animation - ScalarKeyFrameAnimation animation = TargetVisual.Compositor.CreateScalarKeyFrameAnimation((float?)from, (float)to, duration, null, easingFunction); - TargetVisual.StartAnimation(property, animation); - }); - - return this; - } + protected override IAnimationBuilder OnTranslation(Axis axis, double? from, double to, Easing ease) => OnScalarAnimation($"Translation.{axis}", from, to, ease); /// - protected override IAnimationBuilder OnTranslation(Vector2? from, Vector2 to, Easing ease = Easing.Linear) - { - AnimationFactories.Add(duration => - { - // Stop the animation and get the easing function - TargetVisual.StopAnimation("Translation"); - CompositionEasingFunction easingFunction = TargetVisual.GetEasingFunction(ease); - - // Create and return the animation - Vector3? from3 = from == null ? default : new Vector3(from.Value, 0); - Vector3 to3 = new Vector3(to, 0); - Vector3KeyFrameAnimation animation = TargetVisual.Compositor.CreateVector3KeyFrameAnimation(from3, to3, duration, null, easingFunction); - TargetVisual.StartAnimation("Translation", animation); - }); - - return this; - } + protected override IAnimationBuilder OnTranslation(Vector2? from, Vector2 to, Easing ease = Easing.Linear) => OnVector3Animation("Translation", from, to, ease); /// - protected override IAnimationBuilder OnOffset(Axis axis, double? from, double to, Easing ease) - { - AnimationFactories.Add(duration => - { - // Stop the animation and get the easing function - string property = $"{nameof(Visual.Offset)}.{axis}"; - TargetVisual.StopAnimation(property); - CompositionEasingFunction easingFunction = TargetVisual.GetEasingFunction(ease); - - // Create and return the animation - ScalarKeyFrameAnimation animation = TargetVisual.Compositor.CreateScalarKeyFrameAnimation((float?)from, (float)to, duration, null, easingFunction); - TargetVisual.StartAnimation(property, animation); - }); - - return this; - } + protected override IAnimationBuilder OnOffset(Axis axis, double? from, double to, Easing ease) => OnScalarAnimation($"{nameof(Visual.Offset)}.{axis}", from, to, ease); /// - protected override IAnimationBuilder OnOffset(Vector2? from, Vector2 to, Easing ease = Easing.Linear) - { - AnimationFactories.Add(duration => - { - // Stop the animation and get the easing function - TargetVisual.StopAnimation(nameof(Visual.Offset)); - CompositionEasingFunction easingFunction = TargetVisual.GetEasingFunction(ease); - - // Create and return the animation - Vector3? from3 = from == null ? default : new Vector3(from.Value, 0); - Vector3 to3 = new Vector3(to, 0); - Vector3KeyFrameAnimation animation = TargetVisual.Compositor.CreateVector3KeyFrameAnimation(from3, to3, duration, null, easingFunction); - TargetVisual.StartAnimation(nameof(Visual.Offset), animation); - }); - - return this; - } + protected override IAnimationBuilder OnOffset(Vector2? from, Vector2 to, Easing ease = Easing.Linear) => OnVector3Animation(nameof(Visual.Offset), from, to, ease); /// protected override IAnimationBuilder OnScale(double? from, double to, Easing ease) @@ -124,20 +51,9 @@ protected override IAnimationBuilder OnScale(double? from, double to, Easing eas element.GetVisual().CenterPoint = new Vector3((float)(element.ActualWidth / 2), (float)(element.ActualHeight / 2), 0); // Add the scale animation - AnimationFactories.Add(duration => - { - // Stop the animation and get the easing function - TargetVisual.StopAnimation(nameof(Visual.Scale)); - CompositionEasingFunction easingFunction = TargetVisual.GetEasingFunction(ease); - - // Create and return the animation - Vector3? from3 = from == null ? default : new Vector3((float)from.Value, (float)from.Value, 0); - Vector3 to3 = new Vector3((float)to, (float)to, 0); - Vector3KeyFrameAnimation animation = TargetVisual.Compositor.CreateVector3KeyFrameAnimation(from3, to3, duration, null, easingFunction); - TargetVisual.StartAnimation(nameof(Visual.Scale), animation); - }); - - return this; + Vector2? from2 = from == null ? default : new Vector2((float)from.Value, (float)from.Value); + Vector2 to2 = new Vector2((float)to, (float)to); + return OnVector3Animation(nameof(Visual.Scale), from2, to2, ease); } /// @@ -148,15 +64,7 @@ protected override IAnimationBuilder OnRotate(double? from, double to, Easing ea element.GetVisual().CenterPoint = new Vector3((float)(element.ActualWidth / 2), (float)(element.ActualHeight / 2), 0); // Add the rotation animation - AnimationFactories.Add(duration => - { - TargetVisual.StopAnimation(nameof(Visual.RotationAngleInDegrees)); - CompositionEasingFunction easingFunction = TargetVisual.GetEasingFunction(ease); - ScalarKeyFrameAnimation animation = TargetVisual.Compositor.CreateScalarKeyFrameAnimation((float?)from, (float)to, duration, null, easingFunction); - TargetVisual.StartAnimation(nameof(Visual.RotationAngleInDegrees), animation); - }); - - return this; + return OnScalarAnimation(nameof(Visual.RotationAngleInDegrees), from, to, ease); } /// @@ -187,12 +95,24 @@ protected override IAnimationBuilder OnClip(Side side, double? from, double to, } /// - protected override IAnimationBuilder OnSize(Axis axis, double? from, double to, Easing ease) + protected override IAnimationBuilder OnSize(Axis axis, double? from, double to, Easing ease) => OnScalarAnimation($"{nameof(Visual.Size)}.{axis}", from, to, ease); + + /// + protected override IAnimationBuilder OnSize(Vector2? from, Vector2 to, Easing ease = Easing.Linear) => OnVector3Animation(nameof(Visual.Size), from, to, ease); + + /// + /// Schedules a scalar animation targeting the current item + /// + /// The target property to animate + /// The optional starting value for the scalar animation + /// The target value for the scalar animation + /// The easing function to use for the scalar animation + [MustUseReturnValue, NotNull] + private IAnimationBuilder OnScalarAnimation(string property, double? from, double to, Easing ease) { AnimationFactories.Add(duration => { // Stop the animation and get the easing function - string property = $"{nameof(Visual.Size)}.{axis}"; TargetVisual.StopAnimation(property); CompositionEasingFunction easingFunction = TargetVisual.GetEasingFunction(ease); @@ -204,20 +124,27 @@ protected override IAnimationBuilder OnSize(Axis axis, double? from, double to, return this; } - /// - protected override IAnimationBuilder OnSize(Vector2? from, Vector2 to, Easing ease = Easing.Linear) + /// + /// Schedules a vector animation targeting the current item + /// + /// The target property to animate + /// The optional starting value for the vector animation + /// The target value for the vector animation + /// The easing function to use for the vector animation + [MustUseReturnValue, NotNull] + private IAnimationBuilder OnVector3Animation(string property, Vector2? from, Vector2 to, Easing ease) { AnimationFactories.Add(duration => { // Stop the animation and get the easing function - TargetVisual.StopAnimation(nameof(Visual.Size)); + TargetVisual.StopAnimation(property); CompositionEasingFunction easingFunction = TargetVisual.GetEasingFunction(ease); // Create and return the animation Vector3? from3 = from == null ? default : new Vector3(from.Value, 0); Vector3 to3 = new Vector3(to, 0); Vector3KeyFrameAnimation animation = TargetVisual.Compositor.CreateVector3KeyFrameAnimation(from3, to3, duration, null, easingFunction); - TargetVisual.StartAnimation(nameof(Visual.Size), animation); + TargetVisual.StartAnimation(property, animation); }); return this; From 0fe576c417a59ce7bfdd3df20cf10b934932d3fd Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 29 Mar 2019 22:47:56 +0100 Subject: [PATCH 4/5] Fixed the optional starting value for composition animations --- .../Animations/CompositionAnimationBuilder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UICompositionAnimations/Animations/CompositionAnimationBuilder.cs b/UICompositionAnimations/Animations/CompositionAnimationBuilder.cs index ccba239..dad2c4c 100644 --- a/UICompositionAnimations/Animations/CompositionAnimationBuilder.cs +++ b/UICompositionAnimations/Animations/CompositionAnimationBuilder.cs @@ -51,7 +51,7 @@ protected override IAnimationBuilder OnScale(double? from, double to, Easing eas element.GetVisual().CenterPoint = new Vector3((float)(element.ActualWidth / 2), (float)(element.ActualHeight / 2), 0); // Add the scale animation - Vector2? from2 = from == null ? default : new Vector2((float)from.Value, (float)from.Value); + Vector2? from2 = from == null ? default(Vector2?) : new Vector2((float)from.Value, (float)from.Value); Vector2 to2 = new Vector2((float)to, (float)to); return OnVector3Animation(nameof(Visual.Scale), from2, to2, ease); } @@ -141,7 +141,7 @@ private IAnimationBuilder OnVector3Animation(string property, Vector2? from, Vec CompositionEasingFunction easingFunction = TargetVisual.GetEasingFunction(ease); // Create and return the animation - Vector3? from3 = from == null ? default : new Vector3(from.Value, 0); + Vector3? from3 = from == null ? default(Vector3?) : new Vector3(from.Value, 0); Vector3 to3 = new Vector3(to, 0); Vector3KeyFrameAnimation animation = TargetVisual.Compositor.CreateVector3KeyFrameAnimation(from3, to3, duration, null, easingFunction); TargetVisual.StartAnimation(property, animation); From 5e09071472cbe9d745c7b16a871989f9a643cb9c Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 29 Mar 2019 22:49:32 +0100 Subject: [PATCH 5/5] NuGet info updated --- UICompositionAnimations/Properties/AssemblyInfo.cs | 6 +++--- UICompositionAnimations/UICompositionAnimations.nuspec | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/UICompositionAnimations/Properties/AssemblyInfo.cs b/UICompositionAnimations/Properties/AssemblyInfo.cs index d9aa125..6d6795c 100644 --- a/UICompositionAnimations/Properties/AssemblyInfo.cs +++ b/UICompositionAnimations/Properties/AssemblyInfo.cs @@ -23,8 +23,8 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("4.0.1.0")] -[assembly: AssemblyFileVersion("4.0.1.0")] -[assembly: AssemblyInformationalVersion("4.0.1")] +[assembly: AssemblyVersion("4.0.2.0")] +[assembly: AssemblyFileVersion("4.0.2.0")] +[assembly: AssemblyInformationalVersion("4.0.2")] [assembly: ComVisible(false)] diff --git a/UICompositionAnimations/UICompositionAnimations.nuspec b/UICompositionAnimations/UICompositionAnimations.nuspec index a93e4c6..f513e02 100644 --- a/UICompositionAnimations/UICompositionAnimations.nuspec +++ b/UICompositionAnimations/UICompositionAnimations.nuspec @@ -2,7 +2,7 @@ UICompositionAnimations - 4.0.1 + 4.0.2 UICompositionAnimations A wrapper UWP PCL to work with Windows.UI.Composition and XAML animations, and Win2D effects Sergio Pedri @@ -10,7 +10,7 @@ https://github.com/Sergio0694/UICompositionAnimations GPL-3.0-only false - New overloads added, minor bug fixes + New size animation APIs, minor fixes Copyright © 2019 uwp composition animations xaml csharp windows winrt universal app ui win2d graphics