From 163ed96dc040d67c20c0686227b17696840d3540 Mon Sep 17 00:00:00 2001 From: Shaun Lawrence Date: Sun, 11 Jun 2023 15:50:45 +0100 Subject: [PATCH 1/5] Initial work on adding remaining animations --- .../Animations/BaseAnimationTests.cs | 31 ++++++++ .../Animations/FadeAnimationTests.cs | 6 +- .../FlipHorizontalAnimationTests.cs | 7 ++ .../Animations/RotateAnimationTests.cs | 7 ++ .../Animations/ScaleAnimationTests.cs | 7 ++ .../Animations/ShakeAnimationTests.cs | 8 ++ .../Animations/BaseAnimation.shared.cs | 1 + .../Animations/FadeAnimation.shared.cs | 8 +- .../FlipHorizontalAnimation.shared.cs | 29 ++++++++ .../Animations/RotateAnimation.shared.cs | 62 ++++++++++++++++ .../Animations/ScaleAnimation.shared.cs | 48 ++++++++++++ .../Animations/ShakeAnimation.shared.cs | 73 +++++++++++++++++++ .../CommunityToolkit.Maui.csproj | 3 + 13 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 src/CommunityToolkit.Maui.UnitTests/Animations/BaseAnimationTests.cs create mode 100644 src/CommunityToolkit.Maui.UnitTests/Animations/FlipHorizontalAnimationTests.cs create mode 100644 src/CommunityToolkit.Maui.UnitTests/Animations/RotateAnimationTests.cs create mode 100644 src/CommunityToolkit.Maui.UnitTests/Animations/ScaleAnimationTests.cs create mode 100644 src/CommunityToolkit.Maui.UnitTests/Animations/ShakeAnimationTests.cs create mode 100644 src/CommunityToolkit.Maui/Animations/FlipHorizontalAnimation.shared.cs create mode 100644 src/CommunityToolkit.Maui/Animations/RotateAnimation.shared.cs create mode 100644 src/CommunityToolkit.Maui/Animations/ScaleAnimation.shared.cs create mode 100644 src/CommunityToolkit.Maui/Animations/ShakeAnimation.shared.cs diff --git a/src/CommunityToolkit.Maui.UnitTests/Animations/BaseAnimationTests.cs b/src/CommunityToolkit.Maui.UnitTests/Animations/BaseAnimationTests.cs new file mode 100644 index 000000000..5f0eb2f10 --- /dev/null +++ b/src/CommunityToolkit.Maui.UnitTests/Animations/BaseAnimationTests.cs @@ -0,0 +1,31 @@ +using System.Diagnostics; +using CommunityToolkit.Maui.Animations; +using CommunityToolkit.Maui.UnitTests.Mocks; +using FluentAssertions; +using Xunit; + +namespace CommunityToolkit.Maui.UnitTests.Animations; + +public abstract class BaseAnimationTests : BaseTest where TAnimation : BaseAnimation, new() +{ + protected virtual TAnimation CreateAnimation() => new(); + + [Fact] + public async Task LengthShouldDictateFullAnimationLength() + { + var animation = CreateAnimation(); + + Label label = new(); + + label.EnableAnimations(); + + var stopwatch = new Stopwatch(); + stopwatch.Start(); + await animation.Animate(label); + stopwatch.Stop(); + + stopwatch.ElapsedMilliseconds.Should().BeCloseTo(animation.Length, 50); + + stopwatch.Reset(); + } +} diff --git a/src/CommunityToolkit.Maui.UnitTests/Animations/FadeAnimationTests.cs b/src/CommunityToolkit.Maui.UnitTests/Animations/FadeAnimationTests.cs index 6c9ce2537..6dd6cb087 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Animations/FadeAnimationTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Animations/FadeAnimationTests.cs @@ -5,12 +5,12 @@ namespace CommunityToolkit.Maui.UnitTests.Animations; -public class FadeAnimationTests : BaseTest +public class FadeAnimationTests : BaseAnimationTests { [Fact] public async Task AnimateShouldThrowWithNullView() { - FadeAnimation animation = new(); + FadeAnimation animation = CreateAnimation(); var performAnimation = () => animation.Animate(null!); @@ -20,7 +20,7 @@ public async Task AnimateShouldThrowWithNullView() [Fact] public async Task AnimateShouldReturnToOriginalOpacity() { - FadeAnimation animation = new(); + FadeAnimation animation = CreateAnimation(); var label = new Label { diff --git a/src/CommunityToolkit.Maui.UnitTests/Animations/FlipHorizontalAnimationTests.cs b/src/CommunityToolkit.Maui.UnitTests/Animations/FlipHorizontalAnimationTests.cs new file mode 100644 index 000000000..2653a3aa7 --- /dev/null +++ b/src/CommunityToolkit.Maui.UnitTests/Animations/FlipHorizontalAnimationTests.cs @@ -0,0 +1,7 @@ +using CommunityToolkit.Maui.Animations; + +namespace CommunityToolkit.Maui.UnitTests.Animations; + +public class FlipHorizontalAnimationTests : BaseAnimationTests +{ +} diff --git a/src/CommunityToolkit.Maui.UnitTests/Animations/RotateAnimationTests.cs b/src/CommunityToolkit.Maui.UnitTests/Animations/RotateAnimationTests.cs new file mode 100644 index 000000000..42b3179cf --- /dev/null +++ b/src/CommunityToolkit.Maui.UnitTests/Animations/RotateAnimationTests.cs @@ -0,0 +1,7 @@ +using CommunityToolkit.Maui.Animations; + +namespace CommunityToolkit.Maui.UnitTests.Animations; + +public class RotateAnimationTests : BaseAnimationTests +{ +} diff --git a/src/CommunityToolkit.Maui.UnitTests/Animations/ScaleAnimationTests.cs b/src/CommunityToolkit.Maui.UnitTests/Animations/ScaleAnimationTests.cs new file mode 100644 index 000000000..180c4272c --- /dev/null +++ b/src/CommunityToolkit.Maui.UnitTests/Animations/ScaleAnimationTests.cs @@ -0,0 +1,7 @@ +using CommunityToolkit.Maui.Animations; + +namespace CommunityToolkit.Maui.UnitTests.Animations; + +public class ScaleAnimationTests : BaseAnimationTests +{ +} diff --git a/src/CommunityToolkit.Maui.UnitTests/Animations/ShakeAnimationTests.cs b/src/CommunityToolkit.Maui.UnitTests/Animations/ShakeAnimationTests.cs new file mode 100644 index 000000000..5ab7100e3 --- /dev/null +++ b/src/CommunityToolkit.Maui.UnitTests/Animations/ShakeAnimationTests.cs @@ -0,0 +1,8 @@ +using CommunityToolkit.Maui.Animations; + +namespace CommunityToolkit.Maui.UnitTests.Animations; + +public class ShakeAnimationTests : BaseAnimationTests +{ + +} diff --git a/src/CommunityToolkit.Maui/Animations/BaseAnimation.shared.cs b/src/CommunityToolkit.Maui/Animations/BaseAnimation.shared.cs index f827bdc66..897bac4b6 100644 --- a/src/CommunityToolkit.Maui/Animations/BaseAnimation.shared.cs +++ b/src/CommunityToolkit.Maui/Animations/BaseAnimation.shared.cs @@ -1,4 +1,5 @@ namespace CommunityToolkit.Maui.Animations; + /// /// Abstract class for animation types to inherit. /// diff --git a/src/CommunityToolkit.Maui/Animations/FadeAnimation.shared.cs b/src/CommunityToolkit.Maui/Animations/FadeAnimation.shared.cs index 914af71d9..04aae837d 100644 --- a/src/CommunityToolkit.Maui/Animations/FadeAnimation.shared.cs +++ b/src/CommunityToolkit.Maui/Animations/FadeAnimation.shared.cs @@ -20,7 +20,7 @@ public class FadeAnimation : BaseAnimation /// /// Initializes a new instance of . /// - public FadeAnimation() : base(300) + public FadeAnimation() : base(600) { } @@ -41,7 +41,9 @@ public override async Task Animate(VisualElement view) var originalOpacity = view.Opacity; - await view.FadeTo(Opacity, Length, Easing); - await view.FadeTo(originalOpacity, Length, Easing); + var duration = Length / 2; + + await view.FadeTo(Opacity, duration, Easing); + await view.FadeTo(originalOpacity, duration, Easing); } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui/Animations/FlipHorizontalAnimation.shared.cs b/src/CommunityToolkit.Maui/Animations/FlipHorizontalAnimation.shared.cs new file mode 100644 index 000000000..8aa60f40f --- /dev/null +++ b/src/CommunityToolkit.Maui/Animations/FlipHorizontalAnimation.shared.cs @@ -0,0 +1,29 @@ +namespace CommunityToolkit.Maui.Animations; + +/// +/// Animation that will flip the supplied view horizontally. +/// +public class FlipHorizontalAnimation : RotateAnimation +{ + /// + /// Initializes a new instance of . + /// + public FlipHorizontalAnimation() : base(300) + { + + } + + /// + protected override double DefaultRotation { get; set; } = 90; + + /// + public override async Task Animate(VisualElement view) + { + if (view != null) + { + await view.RotateYTo(Rotation, Length, Easing); + await view.RotateYTo(0, Length, Easing); + } + } +} + diff --git a/src/CommunityToolkit.Maui/Animations/RotateAnimation.shared.cs b/src/CommunityToolkit.Maui/Animations/RotateAnimation.shared.cs new file mode 100644 index 000000000..5d819579b --- /dev/null +++ b/src/CommunityToolkit.Maui/Animations/RotateAnimation.shared.cs @@ -0,0 +1,62 @@ +namespace CommunityToolkit.Maui.Animations; + +/// +/// Animation that will rotate the supplied view by the specified . +/// +public class RotateAnimation : BaseAnimation +{ + /// + /// Backing BindableProperty for the property. + /// + public static readonly BindableProperty RotationProperty = + BindableProperty.Create( + nameof(Rotation), + typeof(double), + typeof(RotateAnimation), + 180.0, + BindingMode.TwoWay, + defaultValueCreator: GetDefaultRotationProperty); + + /// + /// Gets or sets the rotation used by the animation. + /// + public double Rotation + { + get => (double)GetValue(RotationProperty); + set => SetValue(RotationProperty, value); + } + + static object GetDefaultRotationProperty(BindableObject bindable) + => ((RotateAnimation)bindable).DefaultRotation; + + /// + /// Initializes a new instance of . + /// + public RotateAnimation() : base(200) + { + } + + /// + /// Initializes a new instance of . + /// + /// The default length of the animation. + protected RotateAnimation(uint defaultLength) : base(defaultLength) + { + } + + /// + /// Gets or sets the default rotation used by the animation. + /// + protected virtual double DefaultRotation { get; set; } = 180.0; + + /// + public override async Task Animate(VisualElement view) + { + if (view != null) + { + await view.RotateTo(Rotation, Length, Easing); + view.Rotation = 0; + } + } +} + diff --git a/src/CommunityToolkit.Maui/Animations/ScaleAnimation.shared.cs b/src/CommunityToolkit.Maui/Animations/ScaleAnimation.shared.cs new file mode 100644 index 000000000..fd8c2b67a --- /dev/null +++ b/src/CommunityToolkit.Maui/Animations/ScaleAnimation.shared.cs @@ -0,0 +1,48 @@ +namespace CommunityToolkit.Maui.Animations; + +/// +/// Animation that will scale the supplied view to the specified and then back down to its original scale. +/// +public class ScaleAnimation : BaseAnimation +{ + /// + /// Backing BindableProperty for the property. + /// + public static readonly BindableProperty ScaleProperty = + BindableProperty.Create( + nameof(Scale), + typeof(double), + typeof(ScaleAnimation), + 1.2, + BindingMode.TwoWay); + + /// + /// Gets or sets the opacity to fade to before returning to the elements current Scale. + /// + public double Scale + { + get => (double)GetValue(ScaleProperty); + set => SetValue(ScaleProperty, value); + } + + /// + /// Initializes a new instance of . + /// + public ScaleAnimation() : base(340) + { + + } + + /// + public override async Task Animate(VisualElement view) + { + ArgumentNullException.ThrowIfNull(view); + + var originalScale = view.Scale; + + var duration = Length / 2; + + await view.ScaleTo(Scale, duration, Easing); + await view.ScaleTo(originalScale, duration, Easing); + } +} diff --git a/src/CommunityToolkit.Maui/Animations/ShakeAnimation.shared.cs b/src/CommunityToolkit.Maui/Animations/ShakeAnimation.shared.cs new file mode 100644 index 000000000..13d4c4032 --- /dev/null +++ b/src/CommunityToolkit.Maui/Animations/ShakeAnimation.shared.cs @@ -0,0 +1,73 @@ +namespace CommunityToolkit.Maui.Animations; + +/// +/// Animation that will shake the supplied view on the x-axis, starting with the +/// and then reducing each time by the . +/// +public class ShakeAnimation : BaseAnimation +{ + /// + /// Backing BindableProperty for the property. + /// + public static readonly BindableProperty StartFactorProperty = + BindableProperty.Create( + nameof(StartFactor), + typeof(double), + typeof(ShakeAnimation), + 15.0, + BindingMode.TwoWay); + + /// + /// Gets or sets the start factor, this is the biggest movement during the shake. + /// + public double StartFactor + { + get => (double)GetValue(StartFactorProperty); + set => SetValue(StartFactorProperty, value); + } + + /// + /// Backing BindableProperty for the property. + /// + public static readonly BindableProperty ReducingAmountProperty = + BindableProperty.Create( + nameof(ReducingAmount), + typeof(double), + typeof(ShakeAnimation), + 5.0, + BindingMode.TwoWay); + + /// + /// Gets or sets the amount to reduce the by on each return to 0 on the x-axis. + /// + public double ReducingAmount + { + get => (double)GetValue(ReducingAmountProperty); + set => SetValue(ReducingAmountProperty, value); + } + + /// + /// Initializes a new instance of . + /// + public ShakeAnimation() : base(300) + { + + } + + /// + public override async Task Animate(VisualElement view) + { + ArgumentNullException.ThrowIfNull(view); + + var duration = (uint)(Length / Math.Ceiling(StartFactor / ReducingAmount)) / 2; + + for (var i = StartFactor; i > 0; i -= ReducingAmount) + { + await view.TranslateTo(-i, 0, duration, Easing); + await view.TranslateTo(i, 0, duration, Easing); + } + + view.TranslationX = 0; + } +} + diff --git a/src/CommunityToolkit.Maui/CommunityToolkit.Maui.csproj b/src/CommunityToolkit.Maui/CommunityToolkit.Maui.csproj index ae639f916..3f6af9e1c 100644 --- a/src/CommunityToolkit.Maui/CommunityToolkit.Maui.csproj +++ b/src/CommunityToolkit.Maui/CommunityToolkit.Maui.csproj @@ -47,6 +47,9 @@ Debug;Release + + false + From ed99dee16fe3af1836e791222e5282ca6629914a Mon Sep 17 00:00:00 2001 From: Shaun Lawrence Date: Sat, 24 Jun 2023 16:55:37 +0100 Subject: [PATCH 2/5] Added FlipVertical --- .../Animations/FlipVerticalAnimationTests.cs | 7 +++++ .../FlipHorizontalAnimation.shared.cs | 1 - .../FlipVerticalAnimation.shared.cs | 28 +++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/CommunityToolkit.Maui.UnitTests/Animations/FlipVerticalAnimationTests.cs create mode 100644 src/CommunityToolkit.Maui/Animations/FlipVerticalAnimation.shared.cs diff --git a/src/CommunityToolkit.Maui.UnitTests/Animations/FlipVerticalAnimationTests.cs b/src/CommunityToolkit.Maui.UnitTests/Animations/FlipVerticalAnimationTests.cs new file mode 100644 index 000000000..b6941f4fc --- /dev/null +++ b/src/CommunityToolkit.Maui.UnitTests/Animations/FlipVerticalAnimationTests.cs @@ -0,0 +1,7 @@ +using CommunityToolkit.Maui.Animations; + +namespace CommunityToolkit.Maui.UnitTests.Animations; + +public class FlipVerticalAnimationTests : BaseAnimationTests +{ +} diff --git a/src/CommunityToolkit.Maui/Animations/FlipHorizontalAnimation.shared.cs b/src/CommunityToolkit.Maui/Animations/FlipHorizontalAnimation.shared.cs index 8aa60f40f..66d280d99 100644 --- a/src/CommunityToolkit.Maui/Animations/FlipHorizontalAnimation.shared.cs +++ b/src/CommunityToolkit.Maui/Animations/FlipHorizontalAnimation.shared.cs @@ -26,4 +26,3 @@ public override async Task Animate(VisualElement view) } } } - diff --git a/src/CommunityToolkit.Maui/Animations/FlipVerticalAnimation.shared.cs b/src/CommunityToolkit.Maui/Animations/FlipVerticalAnimation.shared.cs new file mode 100644 index 000000000..3c168a31e --- /dev/null +++ b/src/CommunityToolkit.Maui/Animations/FlipVerticalAnimation.shared.cs @@ -0,0 +1,28 @@ +namespace CommunityToolkit.Maui.Animations; + +/// +/// Animation that will flip the supplied view vertically. +/// +public class FlipVerticalAnimation : RotateAnimation +{ + /// + /// Initializes a new instance of . + /// + public FlipVerticalAnimation() : base(300) + { + + } + + /// + protected override double DefaultRotation { get; set; } = 90; + + /// + public override async Task Animate(VisualElement view) + { + if (view != null) + { + await view.RotateXTo(Rotation, Length, Easing); + await view.RotateXTo(0, Length, Easing); + } + } +} From 2560b69cfcd46a239fa47a728934277dabcf1e75 Mon Sep 17 00:00:00 2001 From: Shaun Lawrence Date: Sat, 24 Jun 2023 16:57:28 +0100 Subject: [PATCH 3/5] Consistent behaviour when dealing with null --- .../Animations/FlipHorizontalAnimation.shared.cs | 9 ++++----- .../Animations/FlipVerticalAnimation.shared.cs | 9 ++++----- .../Animations/RotateAnimation.shared.cs | 9 ++++----- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/CommunityToolkit.Maui/Animations/FlipHorizontalAnimation.shared.cs b/src/CommunityToolkit.Maui/Animations/FlipHorizontalAnimation.shared.cs index 66d280d99..1083261ca 100644 --- a/src/CommunityToolkit.Maui/Animations/FlipHorizontalAnimation.shared.cs +++ b/src/CommunityToolkit.Maui/Animations/FlipHorizontalAnimation.shared.cs @@ -19,10 +19,9 @@ public FlipHorizontalAnimation() : base(300) /// public override async Task Animate(VisualElement view) { - if (view != null) - { - await view.RotateYTo(Rotation, Length, Easing); - await view.RotateYTo(0, Length, Easing); - } + ArgumentNullException.ThrowIfNull(view); + + await view.RotateYTo(Rotation, Length, Easing); + await view.RotateYTo(0, Length, Easing); } } diff --git a/src/CommunityToolkit.Maui/Animations/FlipVerticalAnimation.shared.cs b/src/CommunityToolkit.Maui/Animations/FlipVerticalAnimation.shared.cs index 3c168a31e..31fb8e9a3 100644 --- a/src/CommunityToolkit.Maui/Animations/FlipVerticalAnimation.shared.cs +++ b/src/CommunityToolkit.Maui/Animations/FlipVerticalAnimation.shared.cs @@ -19,10 +19,9 @@ public FlipVerticalAnimation() : base(300) /// public override async Task Animate(VisualElement view) { - if (view != null) - { - await view.RotateXTo(Rotation, Length, Easing); - await view.RotateXTo(0, Length, Easing); - } + ArgumentNullException.ThrowIfNull(view); + + await view.RotateXTo(Rotation, Length, Easing); + await view.RotateXTo(0, Length, Easing); } } diff --git a/src/CommunityToolkit.Maui/Animations/RotateAnimation.shared.cs b/src/CommunityToolkit.Maui/Animations/RotateAnimation.shared.cs index 5d819579b..600819e00 100644 --- a/src/CommunityToolkit.Maui/Animations/RotateAnimation.shared.cs +++ b/src/CommunityToolkit.Maui/Animations/RotateAnimation.shared.cs @@ -52,11 +52,10 @@ protected RotateAnimation(uint defaultLength) : base(defaultLength) /// public override async Task Animate(VisualElement view) { - if (view != null) - { - await view.RotateTo(Rotation, Length, Easing); - view.Rotation = 0; - } + ArgumentNullException.ThrowIfNull(view); + + await view.RotateTo(Rotation, Length, Easing); + view.Rotation = 0; } } From 40723e4282e01f434d4bb4cbed8a6a6b2771a1db Mon Sep 17 00:00:00 2001 From: Shaun Lawrence Date: Sat, 24 Jun 2023 17:01:16 +0100 Subject: [PATCH 4/5] Added samples for the new types of animation --- .../Behaviors/AnimationBehaviorPage.xaml | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/samples/CommunityToolkit.Maui.Sample/Pages/Behaviors/AnimationBehaviorPage.xaml b/samples/CommunityToolkit.Maui.Sample/Pages/Behaviors/AnimationBehaviorPage.xaml index a835ed682..6a41a1e55 100644 --- a/samples/CommunityToolkit.Maui.Sample/Pages/Behaviors/AnimationBehaviorPage.xaml +++ b/samples/CommunityToolkit.Maui.Sample/Pages/Behaviors/AnimationBehaviorPage.xaml @@ -86,7 +86,62 @@ -