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

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (26投票s)

2008年3月21日

CPOL

4分钟阅读

viewsIcon

107380

downloadIcon

1496

创建动态动画,以及一种简单的方式来重用它们以减小 XAML 代码的大小。

AgDynAnimationsSrc

引言

在这篇简短的文章中,我们将探讨 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 代码。然而,这种过程代码给了我们更多的灵活性,并允许代码重用。换句话说,我们现在可以为 FromToSpeedRatio 属性创建参数,并使用我们需要的任何值。

请注意,我们调用 Storyboard 类上的 SetTargetSetTargetProperty 静态方法来设置双精度动画元素的 **目标元素** 和 **目标属性**。最后一行代码将一个双精度动画元素添加到 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 类定义了 StartStop 公共方法来启动和停止我们的效果,还有一个有用的 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 日:初始发布。
© . All rights reserved.