Silverlight中的动画详解(仅常见问题以及疑难杂症)

此文旨在指出在silverlight动画中出现的问题:

一、当设置完动画即(StoryBoard.Begin()或者加载动画完毕后)后无法设置目标对象属性的值。

标题可能有点绕口,看下下面的代码即可明白:

            Storyboard sb = new Storyboard();
DoubleAnimation animation = new DoubleAnimation();
animation.Duration = TimeSpan.FromSeconds(2);
animation.AutoReverse = true;
animation.From = 100;
animation.To = 400;
Storyboard.SetTarget(animation, myRec);
Storyboard.SetTargetProperty(animation,new PropertyPath("Height"));
sb.Children.Add(animation);
sb.Begin();
            myRec.Height = 300;

上边的代码主要是创建一个Double类型的动画,用于修改myRec(一个Rectangle)的Height。关键问题来了,可以看到在sb.Begin()后边手动修改了myRec的Height属性,

悲剧发生了,你会发现我们这个修改是无效的,之所以造成这个情况是因为动画结束后保持了这个新的属性的值,所以导致了不能再其后修改这个属性的值,不过别担心有解

决的办法。

1.修改Animation的FillBehavior为Stop,这样的话就可以保持一个停止的状态,这样在其后修改属性就可以了

2.给StoryBoard添加Complete事件

    sb.Completed += new EventHandler(sb_Completed);
    void sb_Completed(object sender, EventArgs e)
{
Storyboard sb = sender as Storyboard;
sb.Stop();
myRec.Height = 300;
}

可以看到在Complete事件中调用了StoryBoard的Stop方法将动画停止,然后给属性赋值。

二、动画的RepeatBehavior属性(重复行为),用于设置动画的重复的效果,可以设置为Forever(不停的重复),可以设置为重复的次数,也可以设置为在一定时间内进行重复

设置为重复的次数:

<DoubleAnimation Storyboard.TargetName="cmdGrow" RepeatBehavior="2x"
Storyboard.TargetProperty="Width" To="300" Duration="0:0:5"></DoubleAnimation>

这里设置的是 2x,他的语法就是 num*x,意思就是2次。
后置代码设置方式:

widthAnimation.RepeatBehavior = new RepeatBehavior(2);

 

设置为一定时间内重复:

<DoubleAnimation Storyboard.TargetName="cmdGrow" RepeatBehavior="0:0:13"
Storyboard.TargetProperty="Width" To="300" Duration="0:0:5"></DoubleAnimation>

这里设置为13秒内进行重复。

后置代码设置方式:

widthAnimation.RepeatBehavior = new RepeatBehavior(TimeSpan.FromSeconds(13));



三、FillBehavior属性和AutoReverse属性混合设置

  FillBehavior默认属性为HoldEnd(完成后保持属性的状态),还有一个Stop(完成后保持初始值);

 AutoReverse属性默认值为false,即不会原路返回,可以设置为true进行原路返回。

 

FillBehavior    AutoReverse       

HoldEnd        False                 运行后保持动画后的状态

Stop             Flase                 运行后立马返回初始状态

HoldEnd        True                  运行后会按照原路返回,会忽略HoldEnd的保持

Stop             True                  运行后按照原路返回,和上个效果是一样的

 

四、BeginTime(动画开始时间)和SpeedRatio(动画速率)

BeginTime用来解决多个动画之间的额并发很有效,可以错开多个动画(同一个父级)同时进行。BeginTime可以用来延迟(如果BeginTime为正数)和执行部分(当为负数的时候则在

Duration-BeginTime时间内执行完毕).

 

正的BeginTime值使Timeline的行为延长某个时间。例如,BeginTime为5且Duration为5秒的Timeline整个动画是延迟5秒钟,然后才开始动画的执行。

这个例子的BeginTime为5,动画Duration为5,则动画会延迟5秒钟开始。

<DoubleAnimation Duration="0:0:5"  BeginTime="0:0:5" From="100"  To="300" Storyboard.TargetName="myRec" Storyboard.TargetProperty="Width"></DoubleAnimation>

负的 BeginTime 值使 Timeline(Animation基类) 的行为如同在过去某个时间开始一样。 例如,BeginTime 为 - 2.5 秒且 Duration 为 5 秒的 Timeline 将看起来像是一开始就已完成了一半。

这个例子中的BeginTime为 -2.5,那么整个动画持续时间只有 2.5秒,并且看起来像是一开始就完成了一半。

<ColorAnimation Duration="0:0:5" BeginTime="-0:0:2.5" From="Red" To="Green" Storyboard.TargetName="myRec" Storyboard.TargetProperty="(Fill).(Color)"></ColorAnimation>

时间线的 BeginTime 属性决定时间线的活动期的开始时间。 如果该时间线具有一个父时间线,则 BeginTime 属性决定在其父时间线(ParallelTimeline此类在WPF中提供在Silverlight原生dll中并未发现,定义可以包含子 Timeline 对象的时间段。 这些子时间线将按各自的 BeginTime 属性变为活动状态。 此外,子时间线也可相互重叠(并行运行)。)启动后,该时间线需要多长时间才能启动。

这个例子中ParallelTimeline的BeginTime为5秒,动画的Begin为5秒,那么整个动画将会延迟10秒

<ParallelTimeline BeginTime="0:0:5">
<DoubleAnimation Storyboard.TargetName="DelayedAnimationWithDelayedParentRectangle"Storyboard.TargetProperty="Width"BeginTime="0:0:5"From="100"To="600"Duration="0:0:5"/>
</ParallelTimeline>


SpeedRatio支持动画加速执行,但是这个SpeedRatio不会影响BeginTime,因为动画还是在BeginTime之后执行的。

虽然速率是2,但是整个动画还是在BeginTime5秒之后执行的,因为这个速率仅仅对动画有效,仅仅是BeginTime之后动画的速率。

<DoubleAnimation Duration="0:0:5"  SpeedRatio="2"  BeginTime="0:0:5" From="100"  To="300" Storyboard.TargetName="myRec" Storyboard.TargetProperty="Width"></DoubleAnimation>

 

五、StoryBoard对象

StoryBoard不再过多介绍是干嘛,在此主要介绍其的一些方法

Begin开始动画, Pause (Storyboard)停止动画, Resume继续播放StoryBoard的动画, Seek将StoryBoard移动到指定的时间点,Stop (Storyboard)停止动画.

以上的方法除了Seek之外,其他方法均为直接使用StoryBoard对象调用,看下Seek的调用方法。

  sb.Seek(TimeSpan.FromSeconds(3));

这种方式直接将动画定位到3秒的位置。

fadeStoryboard.Seek(
TimeSpan.FromSeconds(fadeAnimation.Duration.TimeSpan.TotalSeconds/2));

将动画指定到中间的位置(其中的fadeAnimation为Animation)。

 

六、Duration,这个属性竟然也有用错的时候,该属性就是表示一个动画执行过程的时间,格式就是 0:0:0这样的格式,本人在实例过程中由于偷懒仅仅写了一个10,导致动画怎么着也不会执行,最后才发现是Duration的格式错误引起的。

 

 

七、关键帧动画(之前说的几乎都是插值动画的用法,下面介绍复杂的动画关键帧动画,关键帧动画是可以实现更为真实的动画,包括加速度和减速度),线性插值动画是在两个属性值之间进行你给渐变,而一个关键帧动画是可以在任意多个的目标属性值之间进行渐变(这里的意思是线性插值动画通过指定From和To以及By属性让动画在一定的时间内完成动画的,而关键帧动画是通过Value让动画在某一个时间点达到某一个属性的一个值)

关键帧动画元素的名称就是在线性动画的名称后面加上UsingkeyFrames,分别为:

     DoubleAnimationUsingkeyFrames(Doubel关键帧动画)

     ColorAnimationUsingKeyFrames(Color关键帧动画)

     PointAnimationUsingKeyFrames(Point关键帧动画)

以上三种关键帧动画都支持三种不同的关键帧补间类型,分别为Linear(线性),Discrete(离散),Splined(多键),三种格式的作用见下表.

名称

格式

描述

Linear

Linear 类型 KeyFrame

可以使目标属性的值在持续时间内产生固定频率的渐变,其属性值会时时的被反映出来

Discrete

Discrete 类型 KeyFrame

可以使目标属性的值从一个值直接跳到下一个值,这个过程不产生渐变效果,只会显示一个结果.

Splined

Splined 类型 KeyFrame

可以使目标属性值产生精确的渐变,通过keySpline属性可以模拟更真实的动画

 

关键帧动画包含两个重要的属性KeyTime属性和Value属性,作用是在KeyTime属性指定的某个时间点对目标的Value进行控制,KeyTime就是指定在何时达到这个关键帧的Value,切记这里的KeyTime表示的不是这个动画持续多长时间,而是在这个时间点显示的效果是Value,这点和线性插值动画动画中的Duration是不同的(Duration表示这个动画持续多长时间),当然这也是因为线性插值动画在一个动画中是不能有多个动画的,所以其Duration的本质应和KeyTime一致,由于在关键帧中一个动画可以包含多个效果,所以就产生了某一时刻对应的动画.

        <Storyboard x:Name="myStory1">
<!—Linear方式 -->
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="myEllipse1"
Storyboard.TargetProperty
=" (UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)">
<LinearDoubleKeyFrame Value="500" KeyTime="00:00:02"></LinearDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>

 

        <Storyboard x:Name="myStory2">
<!—Discrete方式 -->
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="myEllipse2"  Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)">
                <DiscreteDoubleKeyFrame Value="500" KeyTime="00:00:2.5"></DiscreteDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>

 

这个是难点,这里的Spline比上两个多了一个属性就是KeySpline(获取或设置定义此关键帧的动画进度的两个控制点,两个控制点,用来指定定义关键帧进度的三次方贝塞尔曲线。在描述关键样条时,贝塞尔曲线的起点始终为 0,终点始终为 1,这也就是只定义两个控制点的原因。 所生成的曲线指定如何在一个时间段内内插动画;也就是说,该曲线表示该时间段内动画的目标属性的变化速率。)

 <Storyboard x:Name="myStory3">
                <!Splin方式 -->
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="myEllipse3" BeginTime="00:00:00"
Storyboard.TargetProperty
="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:4.5" KeySpline="0,0 1,0" Value="500"></SplineDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>

 

使用了多个LinearColorKeyFrame进行颜色的渐变

<Storyboard>
<!--使用ColorAnimationUsingKeyFrames-->
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="myEllipse"
Storyboard.TargetProperty
="(Ellipse.Fill).(SolidColorBrush.Color)">
<LinearColorKeyFrame Value="Yellow" KeyTime="00:00:1"></LinearColorKeyFrame>
<LinearColorKeyFrame Value="Red" KeyTime="00:00:2"></LinearColorKeyFrame>
<LinearColorKeyFrame Value="Green" KeyTime="00:00:4"></LinearColorKeyFrame>
</ColorAnimationUsingKeyFrames>
</Storyboard

 

使用了多个LinearPointKeyFrame  进行坐标的变化

<Storyboard>
<PointAnimationUsingKeyFrames Storyboard.TargetName="myEllipse1" Storyboard.TargetProperty="Center" AutoReverse="True">
<LinearPointKeyFrame Value="50,50" KeyTime="0:0:0"></LinearPointKeyFrame>
<LinearPointKeyFrame Value="250,230" KeyTime="0:0:2"></LinearPointKeyFrame>
<LinearPointKeyFrame Value="450,50" KeyTime="0:0:4"></LinearPointKeyFrame>
<LinearPointKeyFrame Value="650,230" KeyTime="0:0:6"></LinearPointKeyFrame>
<LinearPointKeyFrame Value="900,50" KeyTime="0:0:8"></LinearPointKeyFrame>
</PointAnimationUsingKeyFrames>
</Storyboard>


除了上述的三种关键帧动画支持的类型之外还有一种EasingPointKeyFrame(EasingDoubleKeyFrame,EasingColorKeyFrame),就是他,是不是很熟悉呢

没错就是使用了Ease效果的关键帧动画,看个用法。

  <DoubleAnimationUsingKeyFrames>
<EasingDoubleKeyFrame KeyTime="0:0:3" Value="12">
<EasingDoubleKeyFrame.EasingFunction>
<BackEase></BackEase>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>

他们是不能单独使用的,需要配合DoubleAnimationUsingKeyFrames或者ColorAnimationUsingKeyFrames或者PointAnimationUsingKeyFrames来使用,可以指定KeyTime以及Value和最重要的EasingFunction,EasingFunction用法和Ease的用法一样,详情可参见本博客其他文章.



posted @ 2011-10-27 23:01  wangyafei_it  阅读(776)  评论(1编辑  收藏  举报