【问题标题】:How to smooth WPF animation?如何平滑 WPF 动画?
【发布时间】:2012-10-01 08:21:21
【问题描述】:

我正在努力平滑 WPF 动画

其实我的动画代码如下:

private void AnimateX ( FrameworkElement element, double XMoveStart, double XMoveEnd, int secondX)
{

    SineEase eEase = new SineEase();
    eEase.EasingMode = EasingMode.EaseInOut;
    Storyboard sb = new Storyboard();

    DoubleAnimation daX = new DoubleAnimation(XMoveStart, XMoveEnd, new Duration(new TimeSpan(0, 0, 0, secondX, 0)));
    daX.EasingFunction = eEase;
    Storyboard.SetTargetProperty(daX, new PropertyPath("(Canvas.Left)"));

    sb.Children.Add(daX);

    element.BeginStoryboard(sb);
}

上面的代码是一个简单的水平移动对象的方法。当只有一个物体在移动时,就可以了。但是,每当两个或多个对象一起移动时(在前一个动画尚未完成时对另一个对象调用 AnimateX 方法),动画就会开始变得抖动。我所说的抖动是指在动画过程中物体有点晃动。

【问题讨论】:

  • 你知道你的电脑是用软件渲染动画还是硬件加速?
  • 是的,我只是用 RenderCapability 测试它,它是硬件加速的。
  • 您是否让主线程忙于使用 Invokes 进行其他操作?动画在主线程上运行,如果您有一个多线程应用程序,主线程可能会忙于更新 UI 上的其他内容。
  • 是的,我的应用程序是多线程的,它有时也忙于更新其他 UI,但即使我在没有其他 UI 工作的情况下尝试了动画,它仍然有点紧张。
  • 我会在一个单独运行的新应用上尝试你的动画,看看是否有一些后台工作被忽视了。

标签: wpf animation storyboard


【解决方案1】:

我多次遇到同样的问题。我发现根据您添加到画布的对象,WPF 通常必须在每一帧上重新生成这些对象的表示(我相信这可能是您的情况,具体取决于您正在操作的 UI 元素的类型)。您可以通过告诉 WPF 将画布的表示缓存在位图中来解决抖动问题。这在画布的 Xaml 定义中非常简单,如下所示:

<Canvas ...Your canvas properties...>
    <Canvas.CacheMode>
        <BitmapCache />
    </Canvas.CacheMode>
    ...Your objects...
</Canvas>`

这减少了 WPF 应用程序的负载,因为它只是将对象的表示形式存储为位图图像,因此您的应用程序不必在每一帧上重新绘制它们。此解决方案仅适用于您的动画从外部应用到画布,并且没有持续的本地动画应用于画布中绘制的各个对象的情况。如果您的代码中的其他动画相对于彼此移动两个对象,您将需要创建具有自己缓存的单独画布。

请注意,此策略不会缓解某些 UI 元素。但是,我已经看到这种策略对许多元素都有效,包括 TextBoxes 等,以及几何形状。无论如何,它总是值得一试的。

其次,如果缓存本地表示还不够,那么您可能需要查看代码的性能,看看是否有任何进程可能导致暂时阻塞 UI。关于这方面没有统一的解决方案,这取决于还有什么给您的应用程序 UI 带来压力。清理代码并在相关的地方使用异步进程会有所帮助。

最后,如果在所有这些检查之后对您的应用程序的总体需求仍然过高,您可以通过降低其一般帧速率(默认为 60)来消除应用程序的一些压力。您可以尝试 30 或 40 看看如果这通过在初始化中包含以下代码来改善抖动:

Timeline.DesiredFrameRateProperty.OverrideMetadata(typeof(Timeline), new FrameworkPropertyMetadata { DefaultValue = 40 });

【讨论】:

  • 这并没有帮助我平滑一个从左到右移动的简单椭圆(没有 cpu / gpu 负载)。我认为 WPF 绘图很糟糕。
【解决方案2】:

只是一个猜测,但是如果您不使用情节提要直接为属性设置动画会发生什么?

private void AnimateX(FrameworkElement element, double xMoveStart, double xMoveEnd, double durationSeconds)
{
    DoubleAnimation animation = new DoubleAnimation
    {
        From = xMoveStart,
        To = xMoveEnd,
        Duration = TimeSpan.FromSeconds(durationSeconds),
        EasingFunction = new SineEase { EasingMode = EasingMode.EaseInOut }
    };

    element.BeginAnimation(Canvas.LeftProperty, animation);
}

【讨论】:

  • 感谢您的回复。不幸的是,这没有帮助。不过,动画并不流畅。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-27
  • 1970-01-01
  • 2012-09-17
  • 2019-01-19
  • 2011-03-01
  • 2020-08-26
相关资源
最近更新 更多