创建和重用 Silverlight 中的动态动画






4.82/5 (26投票s)
创建动态动画,以及一种简单的方式来重用它们以减小 XAML 代码的大小。
- 运行示例.
引言
在这篇简短的文章中,我们将探讨 Silverlight 动画,并尝试找到一种简单的方法来重用相同的动画以应用于不同的元素。在 XAML 代码中创建动画很容易,但要将相同的动画重用于不同的目标对象并不那么容易。
最坏的情况下,您必须复制相同的 XAML 并为要应用动画的每个对象进行更改。如果您需要创建一个动画,该动画应根据应用该动画的对象而有所不同,那么您将陷入更深的陷阱。
基于以上考虑,我们决定采用一种不同的方式来处理 Silverlight 中的动画。我们需要一种简单而强大的方法来重用动画以应用于不同的对象集。我们还需要一种动态添加动画效果到 Silverlight 对象的方法。
在本文中,我们将介绍解决此问题的一些实现细节。
创建简单的故事板
您可能知道,Silverlight 动画由 Storyboard
类处理。在 XAML 中创建故事板很容易,例如,如果您需要创建一个淡入动画,通常会使用以下 XAML 代码片段:
<Storyboard x:Name="fadeIn">
<DoubleAnimation
Storyboard.TargetName="fadeInEffect"
Storyboard.TargetProperty="(UIElement.Opacity)"
From="0"
To="1"
SpeedRatio="3">
</DoubleAnimation>
</Storyboard>
在这里,我们使用 DoubleAnimation
元素将 UIElement.Opactiry
属性从 0 值动画化到 1,并将 SpeedRatio
设置为 3。Storyboard.TargetName
属性用于指定动画的目标对象。
故事板中可以创建几种其他类型的动画元素,例如,我们也可以使用 DoubleAnimationUsingKeyFrames
元素并在其中创建几个 SplineDoubleKeyFrame
元素。
现在,如果我们想将此动画应用于另一个对象,或者想更改一些动画参数,那么我们将需要复制此 XAML 并对其进行修改以满足我们的需求 – 这并不是我们最终想要达到的目标。
让我们看一个使用 XAML 代码创建的动画的另一个例子:一个放大效果的 XAML 可能看起来像这样:
<Storyboard x:Name="grow">
<DoubleAnimation
Storyboard.TargetName="growEffect"
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
From="1"
To="1.5"
SpeedRatio="3">
</DoubleAnimation>
<DoubleAnimation
Storyboard.TargetName="growEffect"
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
From="1"
To="1.5"
SpeedRatio="3">
</DoubleAnimation>
</Storyboard>
请注意,如果我们想为元素的缩放添加动画,那么我们的目标元素在其 RenderTransform
属性中应具有适当的变换。
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1">
</ScaleTransform>
</TransformGroup>
</Border.RenderTransform>
现在,我们可以通过此字符串引用 ScaleTransform
属性:(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)
。
与其纯粹在 XAML 中创建动画,不如轻松地使用过程代码。这听起来可能是一个坏主意,但事实并非如此。在过程代码中创建故事板是创建和重用 Silverlight 动画的最强大方法。
让我们看一些过程代码,展示我们如何动态创建动画。以下代码显示了如何在过程代码中创建 Storyboard
对象。
Storyboard storyboard = new Storyboard();
DoubleAnimation animation = new DoubleAnimation();
animation.From = 0;
animation.To = 1;
animation.SpeedRatio = 3;
Storyboard.SetTarget(animation, target);
Storyboard.SetTargetProperty(animation, "(UIElement.Opacity)");
storyboard.Children.Add(animation);
上面展示的代码等同于我们创建的 XAML 代码。然而,这种过程代码给了我们更多的灵活性,并允许代码重用。换句话说,我们现在可以为 From
、To
和 SpeedRatio
属性创建参数,并使用我们需要的任何值。
请注意,我们调用 Storyboard
类上的 SetTarget
和 SetTargetProperty
静态方法来设置双精度动画元素的 **目标元素** 和 **目标属性**。最后一行代码将一个双精度动画元素添加到 Storyboard
对象。
为了运行动画,我们需要将故事板添加到我们的目标框架元素。以下是执行此操作的方法:
target.Resources.Add(storyboard);
要开始动画,只需调用 Storyboard
实例上的 Begin
方法。
动态效果类
让我们创建一个动态效果类,该类可用于动态创建故事板,将它们添加到目标框架元素,并在动画完成后删除它们。
这是 DynamicEffect
类的代码:
public abstract class DynamicEffect
{
FrameworkElement target;
Storyboard storyboard;
public DynamicEffect()
{
}
protected abstract Storyboard CreateStoryboard(FrameworkElement target);
protected virtual void Add(FrameworkElement target)
{
this.target = target;
storyboard = CreateStoryboard(target);
storyboard.Completed += new EventHandler(OnCompleted);
target.Resources.Add(storyboard);
}
protected virtual void Remove()
{
if (target == null)
return;
if (storyboard == null)
return;
target.Resources.Remove(storyboard);
target = null;
storyboard = null;
}
protected virtual void OnCompleted(object sender, EventArgs e)
{
Remove();
if (Completed != null)
Completed(sender, e);
}
public virtual void Start(FrameworkElement target)
{
Add(target);
storyboard.Begin();
}
public virtual void Stop()
{
if (target == null || storyboard == null)
return;
storyboard.Stop();
Remove();
}
public event EventHandler Completed;
}
DynamicEffect
类定义了 Start
和 Stop
公共方法来启动和停止我们的效果,还有一个有用的 Completed
事件。
Start
方法会将效果的故事板添加到目标框架元素,然后调用 Begin
来开始动画。反过来,Stop
方法将调用效果的故事板上的 Stop
,然后将其从目标元素中删除。
我们所需要做的就是创建一个派生的效果类,并重写其 CreateStoryboard
虚拟方法。
淡入淡出效果
这是我们如何创建 FadeEffect
类:
public class FadeEffect : DynamicEffect
{
double from;
double to;
double speed;
public FadeEffect(double from, double to, double speed)
{
this.from = from;
this.to = to;
this.speed = speed;
}
protected override Storyboard CreateStoryboard(FrameworkElement target)
{
Storyboard result = new Storyboard();
DoubleAnimation animation = new DoubleAnimation();
animation.From = from;
animation.To = to;
animation.SpeedRatio = speed;
Storyboard.SetTarget(animation, target);
Storyboard.SetTargetProperty(animation, "(UIElement.Opacity)");
result.Children.Add(animation);
return result;
}
}
创建淡入和淡出效果将非常直接。
淡入效果
public class FadeInEffect : FadeEffect
{
public FadeInEffect()
: base(0.0, 1.0, 3.0)
{
}
}
淡出效果
public class FadeOutEffect : FadeEffect
{
public FadeOutEffect()
: base(1.0, 0.0, 3.0)
{
}
}
以下是创建淡入效果并应用它的示例代码:
FadeInEffect effect = new FadeInEffect();
effect.Start(target);
现在,您可以将淡入和淡出效果应用于任意数量的框架元素,而无需复制您的 XAML 代码 :-)
结论
本文的示例代码包含几个使用 XAML 代码创建的动画效果。
在这篇简短的文章中,我们介绍了一些简单的动态效果;但是,也可以使用动画变换和剪辑属性来创建更复杂的效果。也可以将简单的效果链接起来以实现一些复杂的功能,例如创建轮播效果。
我计划发布更多关于 Silverlight 动画效果的文章,请告诉我您希望在未来的文章中看到什么。
关注点
- 为变换和剪辑属性添加动画。
- 创建动画链。
- 使用关键帧拆分来创建非线性动画效果。
历史
- 2008 年 3 月 21 日:初始发布。