在 .NET 控件中应用动画效果
一些动画效果可以让您的应用程序更具吸引力。
引言
有时,几行代码就能让应用程序更具吸引力。在本文中,我想介绍一个简单的库,用于在 .NET 控件中应用动画效果。但是要注意,不要同时激活太多动画效果,否则可能会导致您的 Pocket PC/Windows CE 应用程序运行缓慢。
算法
定期更改控件的位置和/或尺寸可以呈现一些有趣的动画效果。所有动画效果都可以通过以下步骤实现:
- 确定初始和最终位置/尺寸。
- 初始化参数,例如间隔、步数等。
- 预先计算动画生命周期中的位置/尺寸。
- 触发计时器以启动动画。
- 每当计时器被唤醒时,将目标控件的位置/尺寸更改为预先计算的值。
- 一旦动画状态发生变化,它应该通过事件通知所有监听器。
本文演示了三种基本的动画效果:移动、缩放和旋转。对于每种效果,它都包括三种运动:匀速运动、加速运动和减速运动。匀速运动很容易实现,所以我们只讨论一下加速运动,顺便说一下,减速运动也遵循相同的原理。
对于移动动画的加速运动,我们假设从 **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 下载最新的演示。