飘遥的Blog

C/C++/.NET
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

乱弹琴 Silverlight 2.0 (18) 动画(Animation)

Posted on 2008-05-05 02:00  Zzx飘遥  阅读(822)  评论(0编辑  收藏  举报
前言:Silverlight 2.0 Beta1 已经发布,加入了许多激动人心的新特性:WPF UI 框架、丰富的控件、丰富的网络支持、丰富的基础类库支持等。这是本人的学习笔记,写的比较乱,因此定名为乱弹琴Silverlight 2.0 系列文章。

本篇介绍动画(Animation)的内容。

处理动画的命名空间主要为:System.Windows.Media.Animation

主要类的继承层次为:
System.Object
  System.Windows.DependencyObject
    System.Windows.Media.Animation.Timeline
      System.Windows.Media.Animation.ColorAnimation
     System.Windows.Media.Animation.ColorAnimationUsingKeyFrames
     System.Windows.Media.Animation.DoubleAnimation
     System.Windows.Media.Animation.DoubleAnimationUsingKeyFrames
     System.Windows.Media.Animation.ObjectAnimationUsingKeyFrames
     System.Windows.Media.Animation.PointAnimation
     System.Windows.Media.Animation.PointAnimationUsingKeyFrames
     System.Windows.Media.Animation.Storyboard

可见这些类都继承自时间线又称时间轴(Timeline)。
还有些不是继承自时间线的其他类,后面详细介绍。

BeginStoryboard

BeginStoryboard是一个触发器操作,该操作启动 Storyboard 进行动画处理。
XAML:
<Ellipse x:Name="e" Stroke="Red" Fill="Yellow" Width="200" Height="100">
    
<Ellipse.Triggers>
        
<EventTrigger RoutedEvent="Ellipse.Loaded">
            
<BeginStoryboard>
                
<Storyboard>
                    ...
                
</Storyboard>
            
</BeginStoryboard>
        
</EventTrigger>
    
</Ellipse.Triggers>
</Ellipse>

椭圆Loaded完成即触发启动Storyboard。

Storyboard

为容器的子动画提供对象和属性目标信息的容器时间线。这是动画处理中最重要的类之一。
它有Begin()、Pause()、Resume()、Stop()等方法,可以对动画进行控制;有AutoReverse、Duration等属性来设置动画的行为。

<Storyboard>
  ...
</Storyboard>

Color相关的动画类

System.Object
  System.Windows.DependencyObject
    System.Windows.Media.Animation.Timeline
      System.Windows.Media.Animation.ColorAnimation
    System.Windows.Media.Animation.Timeline
      System.Windows.Media.Animation.ColorAnimationUsingKeyFrames
    System.Windows.Media.Animation.ColorKeyFrame
      System.Windows.Media.Animation.DiscreteColorKeyFrame
     System.Windows.Media.Animation.LinearColorKeyFrame
     System.Windows.Media.Animation.SplineColorKeyFrame
    System.Windows.PresentationFrameworkCollection<ColorKeyFrame>
      System.Windows.Media.Animation.ColorKeyFrameCollection

XAML:
<Ellipse x:Name="e" Stroke="Red" Fill="Yellow" Width="200" Height="100">
    
<Ellipse.Triggers>
        
<EventTrigger RoutedEvent="Ellipse.Loaded">
            
<BeginStoryboard>
                
<Storyboard>
                    
<ColorAnimation BeginTime="0:0:0" Storyboard.TargetName="e"
                                    Storyboard.TargetProperty
="(Ellipse.Fill).(SolidColorBrush.Color)"
                                    From
="Yellow" To="White" Duration="0:0:2" AutoReverse="True"
                                    RepeatBehavior
="Forever" >                                
                    
</ColorAnimation>
                
</Storyboard>
            
</BeginStoryboard>
        
</EventTrigger>
    
</Ellipse.Triggers>
</Ellipse>

ColorAnimation:在指定的 Duration 内使用线性内插对两个目标值之间的 Color 属性值进行动画处理。

Storyboard.TargetName:设置要进行动画处理的元素。
Storyboard.TargetProperty:设置要进行动画处理的元素的属性。
From:动画处理的基值。
To:动画处理的目标值。
By:动画处理的目标值为From值和By值的和,当To和By值同时存在时,忽略By值。
Duration:动画从基值到目标值过渡的时间。
AutoReverse:获取或设置一个值,该值指示时间线在完成向前迭代后是否按相反的顺序播放。
RepeatBehavior:获取或设置此时间线的重复行为。一个迭代 Count,指定时间线将要播放的次数;一个 TimeSpan 值,指定此时间线活动周期的总长度;或者特殊值 Forever,指定时间线应该无限重复。默认值是 RepeatBehavior 的 Count 为 1,该值指示时间线播放一次。

ColorAnimationUsingKeyFrames:对指定 Duration 内的一组 KeyFrames 中的 Color 属性值进行动画处理。
关键帧动画的目标值是通过其 KeyFrames 属性定义的,该属性包含 ColorKeyFrame 对象的集合。每个 ColorKeyFrame 都定义一段动画及其自己的目标 Value 和 KeyTime。动画运行时,它将在指定的关键时间从一个关键值移动到下一个关键值。
与 ColorAnimation 不同,ColorAnimationUsingKeyFrames 可以有两个以上的目标值。您还可以控制单个 ColorKeyFrame 段的内插方法。

ColorKeyFrame:有三种类型,分别对应一个支持的内插方法:LinearColorKeyFrame、DiscreteColorKeyFrame 和 SplineColorKeyFrame。

LinearColorKeyFrame:线性内插,基值与目标值平滑过渡。

DiscreteColorKeyFrame:离散内插,到达Duration结束时间点时突然跳跃到目标值。

SplineColorKeyFrame:样条内插,通过设置KeySpline属性,设置两个控制点来控制基值到目标值过渡的快慢,有利于模拟自然界的运动,其原理类似与前面介绍的三次贝塞尔曲线,具体算法可查相关资料。

Double相关的动画和Point相关的动画跟上面Color相关的动画极其相似,使用时可查阅MSDN,在此不多介绍。

示例:刺破气泡的小游戏

XAML:
<Canvas x:Name="LayoutRoot">
    
<Canvas.Resources>
        
<Storyboard x:Name="sbMove" Storyboard.TargetName="position"
                    Storyboard.TargetProperty
="Center">
            
<PointAnimationUsingKeyFrames>
                
<SplinePointKeyFrame x:Name="spFrame" KeyTime="0:0:0.01"
                                     KeySpline
="0.6,0.0 0.9,0.0">                        
                
</SplinePointKeyFrame>
                
<LinearPointKeyFrame x:Name="lnFrame" KeyTime="0:0:0.02">                        
                
</LinearPointKeyFrame>
                
<DiscretePointKeyFrame x:Name="dsFrame" KeyTime="0:0:0.02">                        
                
</DiscretePointKeyFrame>
            
</PointAnimationUsingKeyFrames>
        
</Storyboard>
    
</Canvas.Resources>
    
    
<Canvas.Background>
        
<ImageBrush ImageSource="1.jpg"></ImageBrush>
    
</Canvas.Background>
    
    
<TextBlock Canvas.Left="20" Text="数量:"
               Foreground
="Yellow" FontSize="20"></TextBlock>
    
<TextBlock x:Name="count" Canvas.Left="80" Text="0"
               Foreground
="Yellow" FontSize="20"></TextBlock>
    
    
<Button x:Name="btnFull" Width="80" Height="30"
            Foreground
="Black" Content="全屏" Canvas.ZIndex="10"
            Click
="btnFull_Click" Canvas.Left="120"></Button>
    
    
<Path x:Name="bubble" Canvas.ZIndex="5"
          Stroke
="Transparent" MouseEnter="bubble_MouseEnter">
        
<Path.Fill>
            
<RadialGradientBrush>
                
<GradientStop Color="Transparent" Offset="0.7"></GradientStop>
                
<GradientStop Color="White" Offset="1.0"></GradientStop>
            
</RadialGradientBrush>
        
</Path.Fill>
        
        
<Path.Data>
            
<EllipseGeometry x:Name="position" RadiusX="20"
                             RadiusY
="20" Center="20,20"></EllipseGeometry>
        
</Path.Data>
        
        
<Path.Triggers>
            
<EventTrigger RoutedEvent="Path.Loaded">
                
<BeginStoryboard>
                    
<Storyboard>
                        
<DoubleAnimation Storyboard.TargetName="bubble" Storyboard.TargetProperty="Opacity"
                                          From
="1.0" To="0.5" Duration="0:0:0.5" RepeatBehavior="Forever">
                        
</DoubleAnimation>
                    
</Storyboard>
                
</BeginStoryboard>
            
</EventTrigger>
        
</Path.Triggers>            
    
</Path>
    
<Image x:Name="pointer" Canvas.ZIndex="6" Source="2.png" Width="30" Height="27"></Image>
</Canvas>

C#:

public partial class Page : UserControl
{
    Random rnd
= new Random();
    
int top = 0;
    
int left = 0;
    
int height = 600;
    
int width = 800;
    DispatcherTimer timer
= new DispatcherTimer();

    
public Page()
    {
        InitializeComponent();

        
this.Cursor = Cursors.None;

        timer.Interval
= new TimeSpan(0, 1, 0);
        timer.Tick
+= new EventHandler(timer_Tick);
        timer.Start();
    }

    
void timer_Tick(object sender, EventArgs e)
    {
        timer.Stop();

        
if (Convert.ToInt32(count.Text) > 10)
        {
            HtmlPage.Window.Alert(
"你一分钟刺破气泡的数目为:" + count.Text + " ,继续努力^_^");
        }

        count.Text
= "0";
        timer.Start();
    }


    
private void bubble_MouseEnter(object sender, MouseEventArgs e)
    {
        top
= rnd.Next(20, width - 20);
        left
= rnd.Next(20, height - 40);

        spFrame.Value
= new Point(position.Center.X, top);
        lnFrame.Value
= new Point(left / 2, top);
        dsFrame.Value
= new Point(left, top);

        sbMove.Begin();

        count.Text
= (Convert.ToInt32(count.Text) + 1).ToString();
    }

    
private void LayoutRoot_MouseMove(object sender, MouseEventArgs e)
    {
        Canvas.SetLeft(pointer, e.GetPosition(
this).X);
        Canvas.SetTop(pointer, e.GetPosition(
this).Y);
    }

    
private void btnFull_Click(object sender, RoutedEventArgs e)
    {
        Content contentObject
= Application.Current.Host.Content;
        contentObject.IsFullScreen
= !contentObject.IsFullScreen;
    }
}




ObjectAnimationUsingKeyFrames

ObjectAnimationUsingKeyFrames动画相关的类与上面介绍的类似,对指定 Duration 内的一组 KeyFrames 中的 Object 属性值进行动画处理。
它的Storyboard.TargetProperty属性可以对背景、填充等复杂属性进行动画处理。

结束语

动画处理是Silverlight非常吸引人的一个部分,可以用来实现实验演示、MV、广告等。