0

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.

  1. rotate clockwise a little
  2. return back to normal state.
  3. rotate anticlockwise a little
  4. return back to normal state.

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.

halfer
  • 19,824
  • 17
  • 99
  • 186
Muhammad Touseef
  • 4,357
  • 4
  • 31
  • 75

1 Answers1

1

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 );
Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
  • AnimationSet does not contain a definition for rotate and the best overload wants Ui element, getting this compile error – Muhammad Touseef Feb 14 '18 at 14:46
  • Add a `using Microsoft.Toolkit.Uwp.UI.Animations;` statement to your file – Martin Zikmund Feb 14 '18 at 14:48
  • single rotate doesnt give this error, only chaining is causing so. – Muhammad Touseef Feb 14 '18 at 14:49
  • It should be available as extension method - see https://github.com/Microsoft/UWPCommunityToolkit/blob/master/Microsoft.Toolkit.Uwp.UI.Animations/Extensions/AnimationExtensions.Rotate.cs – Martin Zikmund Feb 14 '18 at 14:50
  • If you manually write `AnimationExtensions.Rotate` is there a overload with `AnimationSet`? – Martin Zikmund Feb 14 '18 at 14:51
  • In that case it should really work, clearly the method is available... You can alternatively call it like this: `AnimationExtensions.Rotate( panel.Rotate( 0.3 ).Then(), -0.3 );` – Martin Zikmund Feb 14 '18 at 15:11
  • can we make it work around the center of the element? without providing the center x and center y? as I posted in the question, I dont know how to provide proper center for the objects because I am scalling them as well, or does scaling doesnt change actual height and width? or should I just provided 0.5 and 0.5? please suggest wht should I do about that thanks – Muhammad Touseef Feb 14 '18 at 15:35
  • It should work with 0.5, 0.5 I think. You can profuse the center in additional parameters of the Rotate method – Martin Zikmund Feb 14 '18 at 15:41
  • is 0.5f converted into 50 pixels? bcz parameters are being asked in pixels, so how can 0.5f mean 50 percent? bcz it will only work in that case – Muhammad Touseef Feb 14 '18 at 15:46
  • I think it is 50 percent :-) – Martin Zikmund Feb 15 '18 at 14:03
  • No i tried tht but it is not working so now I am using actual height and width to find out the centers, anyways can you please have a look at my other question regarding this? https://stackoverflow.com/questions/48808483/uwp-gridviewitem-rotate-back-to-default-position – Muhammad Touseef Feb 15 '18 at 15:10