文章出處

Animation規則

基于時間:你設置動畫的初始狀態,最終狀態,及持續時間,Silverlight會計算幀速率。

作用于屬性(properties):一個Silverlight動畫只能做一件事情,在某段時間內修改某個屬性的值。這似乎是一個很大的限制,但你可以通過同時修改多個屬性來創造令人驚訝的動畫效果。

不同的數據類型需要不同的動畫類。比如:Button.Width是double類型的,要創作針對這個屬性的動畫,你就要使用DoubleAnimation類。如果你想改變背景色,你就需要ColorAnimation 類。

Silverlight只有相當有限的幾個Animation 類,你能修改的屬性只限于以下幾種類型:double, object,Color,Point.但是你也可以創建自己的animation類,用于不同的數據類型,你只需要繼承System.Windows.Media.Animation,并指明值是如何隨著時間改變的。

創建簡單動畫

創建一個簡單的動畫是多步驟的過程。你需要三個獨立的成分:執行動畫的對象,管理動畫的故事板,和一個觸發故事板的處理程序。

Animation Class

Silverlight有兩種動畫類,它們都用不同的策略來實現對值的改變。

線性插值:在動畫期間,屬性值連續不斷的平衡變化。(你可以很容易的創建出包含加速與減速的復雜動作)。Silverlight包含三個這樣的類:DoubleAnimation, PointAnimation, and ColorAnimation

關鍵動畫:可以從一個值迅速轉移到另一個值,或者他們可以結合跳躍和線性插值。Silverlight包含四個這樣的類:

ColorAnimationUsingKeyFrames, DoubleAnimationUsingKeyFrames,
PointAnimationUsingKeyFrames, and ObjectAnimationUsingKeyFrames

動畫是通過XAML語言來標記的。雖然動畫類不是元素,但它們可以用相同的XAML語法來創建。例如,下面的標記創建了一個DoubleAnimation:

<DoubleAnimation From="160" To="300" Duration="0:0:5"></DoubleAnimation>

這個動畫持續5秒(就如Duration屬性指明的一樣,它的格式是 Hours:Minutes:Seconds),動畫運行時,它會把目標值從160平穩的改變到300。

然而,上面這段XAML丟失了一個重要的細節:我們并沒有指明要改變的是哪個屬性。這是我們所要說的另一個類--故事板所要做的工作。

The Storyboard Class

故事板管理動畫的時間軸。你可以用故事板來分組多個動畫,并對動畫進行管理--暫停,停止,改變位置。但故事板最基本的特性是它提供了兩個屬性TargetProperty與TargetName來指明動畫作用的屬性與名稱。換言之,故事板是動畫與屬性之間的橋梁。

這里說明如何定義一個故事板,通過DoubleAnimation 來改變名稱為cmdGrow的button的Width屬性。

<Storyboard x:Name="storyboard"
Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Width">
<DoubleAnimation From="160" To="300" Duration="0:0:5"></DoubleAnimation>
</Storyboard>

Storyboard.TargetProperty表明了你想改變的屬性(在這里是width)。如果你不指定一個類名,故事板會使用父元素。如果你想設置附加屬性(例如,Canvas.Left or Canvas.Top),你需要用括號包起來:

<Storyboard x:Name="storyboard"
Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="(Canvas.Left)">
...
</Storyboard>

如果TargetProperty與TargetName都是附加屬性,可以像下面那樣指定:

<Storyboard x:Name="storyboard">
<DoubleAnimation
Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Width"
From="160" To="300" Duration="0:0:5"></DoubleAnimation>
</Storyboard>

上面這種語法更常見,因為它允許你把幾個動畫放在相同的故事板,但每個動畫設置不同的元素和屬性。雖然你不能同時改變多個動畫的同一個屬性,但你可以(比較經常的)同時改變同一個對象的不同屬性

 Starting an Animation with an Event Trigger

定義一個故事板和動畫對象是創建動畫的第一步。要使故事板生效,你需要一個事件觸發器。一個事件觸發器響應故事板的執行事件。目前Silverlight通過BeginStoryboard來啟動

故事板(包括它包含的動畫)。

下面的例子使用頁面的觸發器集合附加一個加載動畫事件。當Silverlight內容第一次呈現在瀏覽器中,且元素已加載完成,button就開始變形。5s之內,它的寬度由160變到300.

<UserControl ... >
<UserControl.Triggers>
<EventTrigger>
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="cmdGrow"
Storyboard.TargetProperty="Width"
From="160" To="300" Duration="0:0:5"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</UserControl.Triggers>
<Grid x:Name="LayoutRoot" Background="White">
<Button x:Name="cmdGrow" Width="160" Height="30"
Content="This button grows"></Button>
</Grid>
</UserControl>

不幸的是,相對于WPF事件,Silverlight有著及大的限制。Silverlight只支持頁面第一次創建的時候觸發Loaded事件。對于其它事件不能作出相應的響應,比如點擊,按鍵和鼠標移動。

Starting an Animation with Code

在代碼中,我們可以通過任意事件與故事板交互來啟動Silverlight動畫。我們要做的第一步,便是把故事板移到資源文件中。

<UserControl ... >
<UserControl.Resources>
<Storyboard x:Name="storyboard">
<DoubleAnimation
Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Width"
From="160" To="300" Duration="0:0:5"></DoubleAnimation>
</Storyboard>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<Button x:Name="cmdGrow" Width="160" Height="30" Click="cmdGrow_Click"
Content="This button grows"></Button>
</Grid>
</UserControl>

現在故事板有了一個名字,你可以在你的代碼中操作它了。如:

private void cmdGrow_Click(object sender, RoutedEventArgs e)
{
storyboard.Begin();
}

單擊按鈕,啟動動畫,按鈕的寬度會從160px拉伸到300px,如下圖所示:

Configuring Animation Properties

 要深入了解Silverlight動畫,你需要仔細看看那些看似簡單的基本屬性,包括From,To,Duration等。

FROM

From用來設置起始值。有前面的例子中,動畫起始于160px.因些,每次你單擊按鈕啟動動畫,寬度會重置為160px,動畫再次運行。即使你單擊的時候,剛好有一個動畫正在運行也是如此。(這也說明一個Silverlight動畫細節:依賴屬性只難存在于一個動畫,當你開始第二個動畫的時候,第一個動畫便被丟棄)。

如果你在上面的例子中移除掉From屬性,你可以多次單擊按鈕而不會將動畫重置。每點一次,都開始一個新動畫,在當前值開始變動。但是,當按鈕到達最大值時,繼續點擊會變得無效,除非你讓按鈕回到原始值。

在上面的例子中,我們還可以設置ActualWidth屬性,表示按鈕的當前寬度。你不能用動畫來改變它,因為它是只讀的,但你可以用它來設置動畫的起始位置。

TO

就如可以省略FROM屬性一樣,我們也可以省略TO屬性。如:

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

乍一看,這似乎什么都做不了,因為這既沒有設置FROM屬性與沒有設置TO屬性,他們都是相同的值。但這里有一個微妙且重要的區別。

當我們省略FROM時,Silverlight會將元素的當前值考慮到動畫中,如前面例子中按鈕的當前寬度。然而,當我們省略TO屬性時,Silverlight豪不猶豫的使用當前值,即TO屬性會變成最初的那個值。

BY

我們也可以使用BY屬性,而不是TO。動畫可以通過BY屬性設置每一次的變化量,而不是最動畫最終的值。比如,你可以通過BY屬性,將當前寬度每次增加10PX.

<DoubleAnimation Storyboard.TargetName="cmdGrow" By="10"
Storyboard.TargetProperty="Width" Duration="0:0:5"></DoubleAnimation>

BY屬性并不適合所有的非數值改變的動畫類,比如ColorAnimation。

Duration

Duration表示動畫從開始到結束之間的時間間隔。Duration屬性的值要求是Duration類型的,類似TimeSpan。事實上,Duration類型可以隱匿的通過TimeSpan類型轉換過來。

widthAnimation.Duration = TimeSpan.FromSeconds(5);

為什么微軟要設置Duration類型,而不直接使用TimeSpan?因為Duration有兩個特別的值是不能TimeSpan來表示的:Duration.Automatic與Duration.Forever。Duration.Automatic表示1s的持續時間,而Duration.Forever則表示永遠的,這會讓動畫不產生任何影響。

Animation Lifetime

技術上來說Silverlight動畫都是暫時的,這意味著它們不改變對象的基本特征。一旦啟動了一個動畫,它只是改覆蓋了屬性的當前值。因為這就是依賴屬性的工作方式,這是一個很容易忽略的細節,并極易造成混亂。

一個單向動畫(就像上面中按鈕寬度的增長),當它完成運行后仍然是活動的。這是因為動畫需要保持按鈕寬度在新的尺寸。這會導致一個很常見的問題:當你在動畫完成后,用代碼修改屬性的值,你的代碼似乎沒有任何影響。你的代碼分配了一個新的本地值,但動畫擁有較高的優先級。

對于這個問題,有下面幾種解決方法:

1.創建一個動畫,將你的元素設置城初始狀態:這種方法不能設置TO屬性。

2.創建一個可逆的動畫:設置AutoReverse屬性為true.

3.改變FillBehavior屬性:通常,將FillBehavior屬性設置HoldEnd,意味著動畫結束時,目標屬性就會回到原來的值。

4.動畫結束時回收動畫對象:在Completed事件中處理動畫或故事板對象。

這里舉一下第四種做法,在Completed將動畫對象設置為原來的值:

private void storyboard_Completed(object sender, RoutedEventArgs e)
        {
            Storyboard storyboard = (Storyboard)sender;
            storyboard.Stop();
            double currentWidth = cmdGrow.Width;
            storyboard.Stop();
            cmdGrow.Width = currentWidth;
            
        }

RepeatBehavior

RepeatBehavior屬性允許你控制動畫的重復方式。如果你想指定一個重復次數,用數字表明次數,并緊跟著一個x。例如,下面指明這個動畫重復兩次:

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

在后臺代碼中,可以這樣寫:

widthAnimation.RepeatBehavior = new RepeatBehavior(2);

除了可以設置重復次數外,你還可以設置動畫的重復時間,在該段時間內,動畫會一直重復執行。如:

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

對應的后臺代碼:

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

除此之外,你還可以將RepeatBehavior的值設置成Forever,讓動畫一直不停的運行下去。

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

Simultaneous Animations

故事板有能力管理多個動畫。最重要的是,將這些動畫進行分組,就可以同時啟動這些動畫。

這里我們將兩個動畫放在同一個故事板中,一個動畫作用于按鈕的Width屬性,另一個作用于Height屬性。

    <Storyboard x:Name="storyboard2" Storyboard.TargetName="cmdGrow">
            <DoubleAnimation Storyboard.TargetProperty="Width"
To="300" Duration="0:0:5"></DoubleAnimation>
            <DoubleAnimation Storyboard.TargetProperty="Height"
To="300" Duration="0:0:5"></DoubleAnimation>
        </Storyboard>

有兩個屬于對多個動畫時很有用,一個是BeginTime:控制動畫的開始時間。一個是SpeedRatio:控制動畫的變化速度。

Controlling Playback

Storyboard不單單有begin,end等方法,還有pause(暫停),resume(恢復),Seek(跳轉)等方法。

例如:

Grid設置:

<Grid>
<Image Source="night.jpg"></Image>
<Image Source="day.jpg" x:Name="imgDay"></Image>
</Grid>

故事板設置:

<Storyboard x:Name="fadeStoryboard">
<DoubleAnimation x:Name="fadeAnimation"
Storyboard.TargetName="imgDay" Storyboard.TargetProperty="Opacity"
From="1" To="0" Duration="0:0:10">
</DoubleAnimation>
</Storyboard>

后臺代碼:

private void cmdStart_Click(object sender, RoutedEventArgs e)
{
fadeStoryboard.Begin();
}
private void cmdPause_Click(object sender, RoutedEventArgs e)
{
fadeStoryboard.Pause();
}
private void cmdResume_Click(object sender, RoutedEventArgs e)
{
fadeStoryboard.Resume();
}
private void cmdStop_Click(object sender, RoutedEventArgs e)
{
fadeStoryboard.Stop();
}
private void cmdMiddle_Click(object sender, RoutedEventArgs e)
{
// Start the animation, in case it's not currently underway.
fadeStoryboard.Begin();
// Move to the time position that represents the middle of the animation.
fadeStoryboard.Seek(
TimeSpan.FromSeconds(fadeAnimation.Duration.TimeSpan.TotalSeconds/2));
}

private void sldSpeed_ValueChanged(object sender, RoutedEventArgs e)
{
// To nothing if the page is still being initialized.
if (sldSpeed == null) return;
// This also restarts the animation if it's currently underway.
fadeStoryboard.SpeedRatio = sldSpeed.Value;
lblSpeed.Text = sldSpeed.Value.ToString("0.0");
}

 

效果如圖:

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()