I am trying to get a shaking (or jiggle effect) on a UI element in my uwp app by using animations from UWP Community toolkit. If I put a single rotation animation on it, it works perfect like expected. But I am actually trying to chain them up and then put them in a loop within an event so the ui element loops like it is shaking.
So for that purpose I am trying following code.
var parent = panel?.Parent as UIElement;
if (parent != null)
{
while (true)
{
var animation = new RotationAnimation() { To = 0.3, Duration = TimeSpan.FromMilliseconds(100) };
animation.StartAnimation(panel);
var animation2 = new RotationAnimation() { From = 0.3, To = 0, Duration = TimeSpan.FromMilliseconds(100) };
animation2.StartAnimation(parent);
var animation3 = new RotationAnimation() { To = -0.3, Duration = TimeSpan.FromMilliseconds(100) };
animation3.StartAnimation(panel);
var animation4 = new RotationAnimation() { From = -0.3, To = 0, Duration = TimeSpan.FromMilliseconds(100) };
animation4.StartAnimation(parent);
}
}
as you can see I am getting my UI element from some logic and then I am trying to chain 4 rotationAnimations 1 after the other.
this should creates the jiggle effect I want, but my app actually hangs ( and I don't get any exceptions) even when I try to do it without the while loop. I am trying to create this first and then I aim to make it asyncronous in a function so that I can call it on an element and then stop the animation from another event or method.
I am getting a sense that maybe this is not the right way to chain these animations from UWP Community toolkit that's why the UI is freezing and there is a better way to do this?
Also I do know about the extension method like, panel.Rotate() which is also provided by community toolkit, but I don't want to use them because I have to provide centerX and centerY of the panel, and I am using the scale animations already on the same objects in some other scenario, so I am not sure how to provide the centerX and centerY of the UI element.
Also I am using extensions:VisualEx.NormalizedCenterPoint="0.5,0.5,0" on that specific ui element, that is why I am a little confused to provide the center points, hence want to use this RotationAnimation class which doesn't take any central points and automatically detects center points as the center of the element probably because of that xaml property I've set.
The problem here is that StartAnimation
does not wait for the animation to complete. When you run the code, it will actually try to run all the animations at the same time. And that gets even worse when you do it in a while (true)
block, because this will repeat the process infinitely, so it may try to launch hundreds of animations at the same time.
As a quick fix you could add a await Task.Delay( 100 )
call between the individual phases to make sure the UI waits for the animation to complete. But this solution is not very good at it depends on Task.Delay
and the animation will not run 100 % reliably after exactly 100 milliseconds.
Better solution to run the next animation in the Completed
event of the previous one:
animation.Completed += YourHandler;
However why should we reinvent the wheel? We can use AnimationSet
provided by the toolkit itself!
AnimationSet
The AnimationSet
class allows you to create complex animations and chain them one by one. For this you can utilize the Then
method that will wait for the previous animation to finish before starting then next one. See the source code.
var animationSet = panel.Rotate( 0.3 )
.Then()
.Rotate( -0.3 )
.Then()
.Rotate( 0.3 )
.Then()
.Rotate( -0.3 );