天天看點

Silverlight & Blend動畫設計系列五:故事闆(StoryBoards)和動畫(Animations)

  正如你所看到的,Blend是一個非常強大的節約時間的設計工具,在Blend下能夠設計出很多滿意的動畫作品,或許他具體是怎麼實作的,通過什麼方式實作的我們還是一無所知。本篇将續前面幾篇基礎動畫之上,詳細介紹Silverlight裡提供故事闆(StoryBorards)的屬性和各種不同類型的動畫(Animations)的詳細知識點,揭曉在Blend下設計動畫的内幕故事。

一、故事闆(StoryBoard)屬性

  Silvelight中的故事闆(StoryBoard)提供了管理時間線的功能接口,可以用來控制一個或多個Silverlight動畫程序,故我也稱其為動畫時間線容器。如下XAML代碼塊示範了通過StoryBoard來管理了名為GreenBall的元素在X坐标方向上的偏移變換動畫。

<Storyboard x:Name="MoveBall">

    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="GreenBall" 

        Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">

        <EasingDoubleKeyFrame KeyTime="00:00:02" Value="540"/>

    </DoubleAnimationUsingKeyFrames>

</Storyboard>

   StoryBoard提供了六個常用的動畫屬性選項,它們分别是:AutoReverse,BeginTime,Duration,FillBehavior,RepeatBehavior,SpeedRatio。通過這六個屬性可以用來控制動畫的基本行為動作,比如想要實作動畫的緩沖時間,就需要用到Duration屬性;設定動畫的開始時間則用BeginTime;如果動畫執行完後根據執行路線反向執行到原始狀态則需要使用AutoReverse;如果需要設定動畫的運作速度則使用SpeedRatio就可以完成。以下代碼塊示範了AutoReverse屬性的使用,動畫運作完後将按着原來的運作路線進行反向運作。更多詳細可參考這篇博文介紹:《動畫基礎快速入門Animation》或者MSDN。

<Storyboard x:Name="MoveBall" AutoReverse="True">

   Storyboard的屬性是可以組合應用的,如上代碼塊給動畫設定了AutoReverse屬性,使其在動畫執行完後通過原來的運作路徑進行復原動畫,可以給該動畫時間線容器添加一個BeginTime屬性,使其在程式加載後5秒鐘才開始執行動畫,這樣就使用到了兩個屬性,如下代碼塊:

<Storyboard x:Name="MoveBall" AutoReverse="True" BeginTime="00:00:05">

    ......

二、動畫類型(Types of animation)

  Silverlight中的動畫主要分From/To/By和關鍵幀動畫兩種類型。

  From/To/By動畫也稱為線性插值動畫(Linear Interpolation),是Silverlight類型中最簡單的一種動畫,隻需要設定開始(From)、結束(To)和動畫值(By)就可以完成動畫的建立,Silverlight 3中提供了三種基礎的From/To/By動畫類型:DoubleAnimation、ColorAnimation和PointAnimation.

  關鍵幀動畫比From/To/By動畫更加強大,無需指定動畫的開始、結束以及動畫緩沖時間等相關參數,隻需要關注關鍵幀和如何去控制動畫就行了。Silverlight 3中提供了四種基本的關鍵幀動畫:緩和(Easing)、線性(Linear)、樣條(Spline)和離散(discreet)。

  DoubleAnimation的使用是非常簡單的,隻需要搞清楚From/To/By三要素就基本掌握了該類型動畫的使用,下面是一個簡單的通過DoubleAnimation實作的圓形移動的示例。

<UserControl x:Class="DoubleByAnimation.MainPage"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 

    Width="800" Height="600">

    <UserControl.Resources>

        <Storyboard x:Name="Storyboard1">

            <DoubleAnimation Storyboard.TargetName="Ellipse" 

                Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" 

                From="0" 

                By="150" 

                Duration="00:00:01"/>

        </Storyboard>

    </UserControl.Resources>

    <Canvas x:Name="LayoutRoot" Background="White" >

        <Ellipse Height="200" Width="200" Fill="#FFFF0000" Canvas.Top="181" Canvas.Left="92" RenderTransformOrigin="0.5,0.5" x:Name="Ellipse">

            <Ellipse.RenderTransform>

                <TransformGroup>

                    <ScaleTransform/>

                    <SkewTransform/>

                    <RotateTransform/>

                    <TranslateTransform/>

                </TransformGroup>

            </Ellipse.RenderTransform>

        </Ellipse>

    </Canvas>

</UserControl>

  下面通過一個稍複雜的示例來示範DoubleAnimation動畫的使用,如下動畫代碼塊實作了名稱為Slider對象的X坐标方向的移動動畫:

<Storyboard x:Name="SlideOut">

    <DoubleAnimation Storyboard.TargetName="Slider" 

        Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" 

    Duration="00:00:00.50" To="150"/>

<Storyboard x:Name="SlideIn">

    Duration="00:00:00.50" To="0"/>

  如上動畫定義代碼塊中定義了兩個動畫,一個實作将對象Slider向X坐标方向移動到150像素點的位置,第二個動畫實作将名為Silder的對象向X方向移動到0像素點的坐标位置,這樣其實就實作了一個呈現與不呈現的效果。這裡我們發揮大腦的潛力想象一下,如果Slider是一個面闆對象,通過滑鼠指向和離開的事件使用上面兩個動畫進行控制其不就實作了面闆的滑鼠指向就顯示,離開就退回到原來的位置了?答案卻是如此,詳細見下代碼塊:

public partial class MainPage : UserControl

{

    public MainPage()

    {

        InitializeComponent();

        Slider.MouseEnter += new MouseEventHandler(Slider_MouseEnter);

        Slider.MouseLeave += new MouseEventHandler(Slider_MouseLeave);

    }

    private void Slider_MouseLeave(object sender, MouseEventArgs e)

        SlideIn.Begin();

    private void Slider_MouseEnter(object sender, MouseEventArgs e)

        SlideOut.Begin();

}

        

   通過上面的示例,是否覺得要在Silverlight中實作一個動畫是非常簡單的?上面的示例就是掩飾了如何使用From/To/By的DoubleAnimation實作了對象的移動動畫,同樣也可以使用關鍵幀動畫(DoubleUsingKeyframes)來實作這一功能。如下代碼片段示範了元素Silder向X坐标方向移動到150像素點。

Storyboard MoveRight = new Storyboard();

DoubleAnimationUsingKeyFrames Anim = new DoubleAnimationUsingKeyFrames();

Storyboard.SetTargetName(Anim, "Slider");

Anim.SetValue(Storyboard.TargetPropertyProperty, 

    new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"));

Anim.BeginTime = new TimeSpan(0, 0, 0);

SplineDoubleKeyFrame SKeyFrame = new SplineDoubleKeyFrame();

SKeyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0.5));

SKeyFrame.Value = 150;

Anim.KeyFrames.Add(SKeyFrame);

MoveRight.Children.Add(Anim);

......

  ColorAnimation類型動畫主要應用于顔色上的變換動畫效果,比如有一個圓,預設的填充顔色是紅色(Red),設計一個動畫通過2秒鐘的動畫換成将圓的填充顔色變換為藍色。

<Ellipse Height="218" Width="218" Canvas.Left="294" Canvas.Top="195" Fill="#FFFF0000" Cursor="Hand" x:Name="RedEllipse"/>

  可以通過Blend的設計器來完成這樣的動畫的建立,在對象和時間軸面闆裡建立動畫容器時間線,然後選中RadEllipse圓形對象在0秒的時間線上填充其顔色為紅色,2秒的時間線上填充其顔色為藍色,詳細設計如下圖:

  Blend最終生成的XAML代碼如下:

<Storyboard x:Name="Storyboard1">

    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="RedEllipse" 

        Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">

        <EasingColorKeyFrame KeyTime="00:00:00" Value="Red"/>

        <EasingColorKeyFrame KeyTime="00:00:02" Value="Blue"/>

    </ColorAnimationUsingKeyFrames>

   有Blend這樣強大的設計工具是很幸運的,對于設計人員來說要實作一些動畫需求直接通過界面設計就完成了。對于程式員來說就煩惱了,由于不熟悉設計工具,要實作某種動畫隻能通過編寫程式代碼來完成,這将是一個很龐大的工程,比如說當滑鼠指向一圓的時候其填充顔色慢慢的向藍色(Blue)漸變,滑鼠離開的時候慢慢的恢複其預設顔色紅色。實作這動畫效果則需要寫上如下長篇的程式代碼:

private Storyboard TurnBlue = new Storyboard();

private Storyboard TurnRed = new Storyboard();

private ColorAnimation BlueColor = new ColorAnimation();

private ColorAnimation RedColor = new ColorAnimation();

public MainPage()

    InitializeComponent();

    BlueColor.SetValue(Storyboard.TargetNameProperty, "RedEllipse");

    BlueColor.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath("(Shape.Fill).(SolidColorBrush.Color)"));

    BlueColor.To = Colors.Blue;

    TurnBlue.Children.Add(BlueColor);

    LayoutRoot.Resources.Add("TurnBlue", TurnBlue);

    RedColor.SetValue(Storyboard.TargetNameProperty, "RedEllipse");

    RedColor.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath("(Shape.Fill).(SolidColorBrush.Color)"))

    RedColor.To = Colors.Red;

    TurnRed.Children.Add(RedColor);

    LayoutRoot.Resources.Add("TurnRed", TurnRed);

    RedEllipse.MouseEnter += (senderRed, eRed) =>

        {

            TurnRed.Begin();

        };

    RedEllipse.MouseLeave += (senderBlue, eBlue) =>

            TurnBlue.Begin();

  這樣的代碼實作其實就是用程式代碼建立了兩個動畫,一個由紅色變換到藍色,一個則由藍色變換到紅色,按照前面的方法直接在Blend中設計也是可以的。最終的運作效果如下圖:

  PointAnimation類型動畫更好了解,也就是動畫效果是通過不同的坐标點來控制的。比如說浪濤的效果,下面就以浪濤為示例來示範PointAnimation類型動畫的使用。

代碼

<Storyboard x:Name="Storyboard1" RepeatBehavior="Forever" FillBehavior="HoldEnd">

    <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="water" Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.Segments)[1].(BezierSegment.Point2)">

        <EasingPointKeyFrame KeyTime="00:00:00" Value="351.732116699219,36.4064197540283"/>

        <EasingPointKeyFrame KeyTime="00:00:03" Value="415.732116699219,84.4064178466797"/>

    </PointAnimationUsingKeyFrames>

    <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="water" Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.Segments)[1].(BezierSegment.Point3)">

        <EasingPointKeyFrame KeyTime="00:00:00" Value="425.502014160156,32.8349914550781"/>

        <EasingPointKeyFrame KeyTime="00:00:03" Value="489.502014160156,80.8349914550781"/>

    <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="water" Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.Segments)[2].(BezierSegment.Point1)">

        <EasingPointKeyFrame KeyTime="00:00:00" Value="499.271911621094,29.2635669708252"/>

        <EasingPointKeyFrame KeyTime="00:00:03" Value="563.271911621094,77.2635650634765"/>

    <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="water" Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.Segments)[0].(BezierSegment.Point2)">

        <EasingPointKeyFrame KeyTime="00:00:00" Value="112.729011535644,80.834991455078"/>

        <EasingPointKeyFrame KeyTime="00:00:03" Value="104.729011535645,32.8349914550781"/>

    <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="water" Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.Segments)[0].(BezierSegment.Point3)">

        <EasingPointKeyFrame KeyTime="00:00:00" Value="185.502014160156,80.834991455078"/>

        <EasingPointKeyFrame KeyTime="00:00:03" Value="177.502014160156,32.8349914550781"/>

    <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="water" Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.Segments)[1].(BezierSegment.Point1)">

        <EasingPointKeyFrame KeyTime="00:00:00" Value="258.275024414062,80.834991455078"/>

        <EasingPointKeyFrame KeyTime="00:00:03" Value="250.275024414063,32.8349914550781"/>

    <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="water" Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.Segments)[2].(BezierSegment.Point2)">

        <EasingPointKeyFrame KeyTime="00:00:00" Value="600.704162597656,72.7879943847655"/>

        <EasingPointKeyFrame KeyTime="00:00:03" Value="608.704162597656,32.8349229097365"/>

    <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="water" Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.Segments)[2].(BezierSegment.Point3)">

        <EasingPointKeyFrame KeyTime="00:00:00" Value="665.502014160156,72.7879943847655"/>

        <EasingPointKeyFrame KeyTime="00:00:03" Value="673.502014160156,32.8349229097365"/>

    <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="water" Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.Segments)[3].(BezierSegment.Point1)">

        <EasingPointKeyFrame KeyTime="00:00:00" Value="730.299926757813,72.7879943847655"/>

        <EasingPointKeyFrame KeyTime="00:00:03" Value="738.299926757813,32.8349229097365"/>

    <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="water" Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.Segments)[3].(BezierSegment.Point2)">

        <EasingPointKeyFrame KeyTime="00:00:00" Value="801.502014160156,40.8349914550781"/>

        <EasingPointKeyFrame KeyTime="00:00:03" Value="801.502014160156,56.8349229097366"/>

    <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="water" Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.Segments)[3].(BezierSegment.Point3)">

    <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="water" Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.Segments)[4].(BezierSegment.Point1)">

    <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="water" Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.StartPoint)">

        <EasingPointKeyFrame KeyTime="00:00:00" Value="1.50201416015619,32.834991455078"/>

        <EasingPointKeyFrame KeyTime="00:00:03" Value="1.50201416015625,88.8349914550779"/>

    <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="water" Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.Segments)[0].(BezierSegment.Point1)">

   關于Silverlight中的動畫相關的理論概論暫時就介紹這些,希望上面的簡單介紹能幫助大家深入的了解和使用Blend進行各種不同的動畫功能設計。更多資訊可查閱下面的推資源連接配接。

本文轉自 beniao 51CTO部落格,原文連結:http://blog.51cto.com/beniao/306067,如需轉載請自行聯系原作者

繼續閱讀