使用 RotationAnimation class 冻结用户界面的循环中的 uwp 旋转动画

uwp rotation animation in a loop with RotationAnimation class freezing UserInterface

我试图通过使用来自 UWP 社区工具包 的动画在我的 uwp 应用程序中的 UI 元素上获得摇晃(或抖动效果)。如果我在上面放一个旋转动画,它会像预期的那样完美地工作。但我实际上是在尝试 将它们链接起来 然后将它们放入一个事件中的循环中,这样 ui 元素就会像摇晃一样循环。

为此,我正在尝试使用以下代码。

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);
    }
}

如您所见,我正在从一些逻辑中获取我的 UI 元素,然后我尝试 链 4 rotationAnimations 1 个接一个。

  1. 顺时针旋转一点
  2. return回到正常状态。
  3. 逆时针旋转一点
  4. return回到正常状态。

这应该会产生我想要的抖动效果,但我的应用程序实际上挂起(而且我没有得到任何exceptions) 即使我尝试在没有 while loop 的情况下这样做。我试图先创建它,然后我的目标是在一个函数中使它成为 asyncronous,这样我就可以在一个元素上调用它,然后从另一个事件或方法停止动画。

我感觉这可能不是从 UWP 社区工具包 链接这些动画的正确方法,这就是为什么 UI 冻结并且有一个更好的方法吗?

我也知道像 panel.Rotate() 这样的扩展方法,它也是由社区工具包提供的,但我不想使用它们,因为我必须提供面板的 centerXcenterY,并且我在其他一些场景中已经在相同对象上使用了缩放动画,所以我我不确定如何提供 UI 元素的 centerX 和 centerY。

此外,我还在那个特定的 ui 元素上使用 extensions:VisualEx.NormalizedCenterPoint="0.5,0.5,0",这就是为什么我是提供中心点有点困惑,因此想使用这个 RotationAnimation class 它不采用任何中心点并自动检测中心点作为元素的中心可能是因为其中 xaml 属性 我已设置。

这里的问题是StartAnimation没有等待动画完成。当您 运行 代码时,它实际上会尝试同时 运行 所有动画。当您在 while (true) 块中执行此操作时,情况会变得更糟,因为这将无限重复该过程,因此它可能会尝试同时启动数百个动画。

作为快速修复,您可以在各个阶段之间添加一个 await Task.Delay( 100 ) 调用,以确保 UI 等待动画完成。但是这个解决方案不是很好,它取决于 Task.Delay 并且动画不会在恰好 100 毫秒后 运行 100% 可靠。

上一个Completed事件中运行下一个动画更好的解决方案:

animation.Completed += YourHandler;

然而我们为什么要重新发明轮子呢?我们可以使用工具包本身提供的AnimationSet

AnimationSet

AnimationSet class 允许您创建复杂的动画并将它们一个接一个地链接起来。为此,您可以使用 Then 方法,该方法将等待上一个动画完成,然后再开始下一个动画。参见 source code.

var animationSet = panel.Rotate( 0.3 )
         .Then()
         .Rotate( -0.3 )
         .Then()
         .Rotate( 0.3 )
         .Then()
         .Rotate( -0.3 );