65.9K
CodeProject 正在变化。 阅读更多。
Home

在 .NET 控件中应用动画效果

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.47/5 (19投票s)

2004 年 5 月 8 日

CPOL

4分钟阅读

viewsIcon

87908

downloadIcon

637

一些动画效果可以让您的应用程序更具吸引力。

Sample Image - AnimatedEffects.gif

引言

有时,几行代码就能让应用程序更具吸引力。在本文中,我想介绍一个简单的库,用于在 .NET 控件中应用动画效果。但是要注意,不要同时激活太多动画效果,否则可能会导致您的 Pocket PC/Windows CE 应用程序运行缓慢。

算法

定期更改控件的位置和/或尺寸可以呈现一些有趣的动画效果。所有动画效果都可以通过以下步骤实现:

  1. 确定初始和最终位置/尺寸。
  2. 初始化参数,例如间隔、步数等。
  3. 预先计算动画生命周期中的位置/尺寸。
  4. 触发计时器以启动动画。
  5. 每当计时器被唤醒时,将目标控件的位置/尺寸更改为预先计算的值。
  6. 一旦动画状态发生变化,它应该通过事件通知所有监听器。

本文演示了三种基本的动画效果:移动、缩放和旋转。对于每种效果,它都包括三种运动:匀速运动、加速运动和减速运动。匀速运动很容易实现,所以我们只讨论一下加速运动,顺便说一下,减速运动也遵循相同的原理。

对于移动动画的加速运动,我们假设从 **n*T** 时刻到 **(n+1)*T** 时刻,目标控件从 Pn 移动到 Pn+1,它们之间的距离应为:**a*(n + 1)^2**,其中 **T** 是周期,**a** 是一个常数。当给出初始位置和最终位置时,很容易确定常数 **a**。

在这个库中,这三种运动的轨迹可以通过一个统一的静态方法 `Procalculate()` 获取。

protected static int[] Precalculate(int val1, int val2, 
        int steps, AnimatedMotions type)
{
    int [] vals = new int[steps];
    int sum = 0, currsum = 0, step, i;
    if (type == AnimatedMotions.UniformMotion) 
        sum = steps;
    else
        for (i = 1; i <= steps; i++) sum += i * i;
    for (i = 1; i < steps; i++)
    {
        step = (type == AnimatedMotions.DeceleratedMotion) 
               ? (steps + 1 - i) * (steps + 1 - i) : 
               (type == AnimatedMotions.UniformMotion ? 1 : i * i);
        currsum += step;
        vals[i - 1] = (val2 - val1) * currsum / sum + val1;
    }
    vals[steps - 1] = val2;
    return vals;
}

使用代码

该库中有四个主要类:`AnimatedEffect`、`MoveAnimatedEffect`、`ZoomAnimatedEffect` 和 `RotateAnimatedEffect`。下面的类图清晰地展示了它们之间的关系。

它们易于使用,并且功能强大,足以生成非常复杂的动画。让我们通过四个案例来了解它们。

1. 简单动画

如果您想将简单的动画效果应用于控件,两行代码就足够了。

MoveAnimatedEffect moveEffect = new MoveAnimatedEffect();
moveEffect.Move(somecontrol, x1, y1, x2, y2, steps, 
           AnimatedMotions.AcceleratedMotion);

这会导致名为 `somecontrol` 的控件以加速运动从原始位置 ( `x1`,`y1` ) 移动到另一个位置 ( `x2`,`y2` )。您可以以同样的方式旋转或缩放控件。真的很简单,不是吗?

2. 级联动画

在大多数情况下,我们希望根据我们的“播放”顺序依次对不同的控件进行动画处理。这时,级联动画应该很有帮助。关键是,一旦前一个动画停止,它就会抛出一个事件;一个控制程序接收它,然后激活下一个动画。例如,我们想将一个控件从 ( `x1`,`y1` ) 移动到 ( `x2`,`y2` ),然后旋转它。它可以这样实现:

MoveAnimatedEffect moveEffect = new MoveAnimatedEffect();
RotateAnimatedEffect rotateEffect = new RotateAnimatedEffect();

moveEffect.Move(somecontrol, x1, y1, x2, y2, 
  steps, AnimatedMotions.AcceleratedMotion);
moveEffect.StateChangedEvent += new 
  AnimationStateChangedEventHandler(NextAnimation);

private void NextAnimation(object sender)
{
    rotateEffect.RotateHorizontally(somecontrol, 
      somecontrol.Width, steps, 
      AnimatedMotions.UniformMotion);
}

3. 并行动画

并行动画允许将多个动画效果应用于一个控件。它可以生成更复杂的动画。例如,我们想同时移动和缩放一个控件。我们只需将以下代码插入程序中:

MoveAnimatedEffect moveEffect = new MoveAnimatedEffect();
ZoomAnimatedEffect zoomEffect = new ZoomAnimatedEffect();

moveEffect.Move(somecontrol, x1, y1, x2, y2, 
  steps, AnimatedMotions.AcceleratedMotion);
zoomEffect.Zoom(somecontrol, somecontrol.Width, 0, 
  somecontrol.Height, 0, steps, 
  AnimatedMotions.UniformMotion);

4. 更复杂的动画

应用前面提到的三种动画,我们可以获得更复杂的动画。在这种情况下,简单的草图会有所帮助。现在,我们想实现这样的动画播放:

上图显示了一系列动画。它包括四个步骤:

  • 步骤 1:将“退出”按钮从上移到底部。
  • 步骤 2:继续将其从右移到左。
  • 步骤 3:将“停止”按钮从上移到底部。
  • 步骤 4:在屏幕中央显示一个图像并旋转它;四个面板出现并围绕它移动,同时它们自身也进行缩放。

以下代码可能会为您实现此类动画播放提供一些提示:

step = 0;
moveEffect.Move(btnExit, 200, - 20, 200, 280, 
    30, AnimatedMotions.AcceleratedMotion); // Step 1
moveEffect.StateChangedEvent += new 
    AnimationStateChangedEventHandler(MainStateChanged);

private void MainStateChanged(object sender)
{
    step ++;
    switch (step)
    {
        case 1:        // Step 2
            moveEffect.Move(btnExit, 200, 280, 
              40, 280, 20, AnimatedMotions.DeceleratedMotion);
            break;
        case 2:        // Step 3
            btnControl.Visible = true;
            moveEffect.Move(btnControl, 200, - 20, 200, 
              280, 30, AnimatedMotions.AcceleratedMotion);
            break;
        case 3:        // Step 4
            labelMoveEffect.Stop();
            label1.Location = new Point(24, 250);
            pictureBox.Visible = true;
            rotateEffect.RotateHorizontally(pictureBox, 
              pictureBox.Width, 20, AnimatedMotions.AcceleratedMotion);
            rotateEffect.StateChangedEvent += new 
              AnimationStateChangedEventHandler(te_TurnOverEvent);
            ChangeImage();
            for (int i = 0; i < 4; i++)
            {
                panels[i].Visible = true;
                panelZoomEffects[i].Start();
            }
            Panels_MovingStopped(null);
            break;
    }
}

您可以下载演示项目以查找其余代码。

结论

对于一个成功的应用程序,要完整、可扩展和稳定并非全部。我们还应该记住:如何提升用户体验。当我们的用户不得不面对数十个具有相同界面的应用程序时,一点动画可以让您的应用程序与众不同,并让您的用户感到高兴。为什么不尝试一下呢?

历史

您始终可以从 OpenVue.net 下载最新的演示。

© . All rights reserved.