線性關鍵影格動畫、具有 KeySpline 值的關鍵影格動畫或緩動函式是大致相同案例的三種不同技術:建立稍微複雜的分鏡腳本動畫,並使用從開始狀態到結束狀態的非線性動畫行為。
先決條件
確定您已閱讀分鏡動畫主題。 本主題以 分鏡腳本動畫 中說明的動畫概念為基礎,不會再討論。 例如, 分鏡腳本動畫 描述如何以動畫為目標、分鏡腳本作為資源、 Timeline 屬性值,例如 Duration、 FillBehavior 等等。
使用關鍵影格動畫製作動畫
關鍵影格動畫可以在動畫時間軸中的某個時刻使多個目標值被達成。 換句話說,每個關鍵幀可以指定一個不同的中間值,最後到達的關鍵幀是最終的動畫值。 透過指定多個要製作動畫的值,您可以製作更複雜的動畫。 關鍵影格動畫還支持不同的插補邏輯,且每種動畫類型的插補邏輯都會實作為不同的 KeyFrame 子類別。 具體而言,每個關鍵影格動畫類型都有其 KeyFrame 類別的離散、線性、樣條和緩動變化,以指定其關鍵影格。 例如,若要指定以 Double 為目標並使用關鍵影格的動畫,您可以使用 DiscreteDoubleKeyFrame、 LinearDoubleKeyFrame、 SplineDoubleKeyFrame 和 EasingDoubleKeyFrame 來宣告關鍵影格。 您可以在單一 KeyFrames 集合中使用所有這些類型中的任何一種,從而在每次達到新關鍵影格時改變插補方式。
對於插補行為,每個關鍵幀都會控制插補,直到達到其 KeyTime 時間為止。 它的 價值 也在那個時候達到。 如果超出此範圍還有更多關鍵影格,則該值會成為序列中下一個關鍵影格的起始值。
在動畫開始時,如果沒有 KeyTime 為 "0:0:0" 的關鍵影格存在,則起始值將是該屬性的非動畫值。 這類似於「從//到」動畫在沒有「從」時的行為方式。
關鍵影格動畫的持續時間隱含地等於其任何關鍵影格中設定的最高 KeyTime 值的持續時間。 如果需要,您可以設定明確的 持續時間 ,但請注意它不能短於您自己的關鍵幀中的 KeyTime ,否則您會切斷部分動畫。
除了 持續時間 之外,您還可以在關鍵影格動畫上設定所有以 Timeline 為基礎的屬性,就像在 從/到/By 動畫中一樣,因為關鍵影格動畫類別也衍生自 Timeline。 這些包括:
- 自動反轉:一旦到達最後一個關鍵影格,幀就會以與結尾相反的順序重複。 這會使動畫的表觀持續時間加倍。
- BeginTime:延遲動畫的開始。 在達到 BeginTime 之前,影格中 KeyTime 值的時間軸不會開始計算,因此沒有切斷影格的風險
- FillBehavior:控制當到達最後一個關鍵影格時的行為。 FillBehavior 對任何中間關鍵影格沒有影響。
-
RepeatBehavior :
- 如果設定為 「永久」,則關鍵影格及其時間軸會無限重複。
- 如果設定為疊代計數,時間軸會重複多次。
- 如果設定為 持續時間,則時間軸會重複,直到達到該時間為止。 如果動畫不是時間軸隱含持續時間的整數因數,這可能會在關鍵影格序列的中途截斷動畫。
- SpeedRatio (不常用)
線性關鍵影格
線性關鍵影格會導致值的簡單線性插補,直到達到影格的 KeyTime 為止。 此插補行為最類似於分鏡腳本動畫主題中所述的更簡單的 //By 動畫。
以下是如何使用關鍵影格動畫,使用線性關鍵影格來縮放矩形的轉譯高度。 此範例會執行動畫,其中矩形的高度會在前 4 秒內稍微線性增加,然後在最後一秒快速縮放,直到矩形是起始高度的兩倍為止。
<StackPanel>
<StackPanel.Resources>
<Storyboard x:Name="myStoryboard">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="myRectangle"
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
<LinearDoubleKeyFrame Value="1" KeyTime="0:0:0"/>
<LinearDoubleKeyFrame Value="1.2" KeyTime="0:0:4"/>
<LinearDoubleKeyFrame Value="2" KeyTime="0:0:5"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</StackPanel.Resources>
</StackPanel>
離散關鍵影格
離散關鍵影格不使用任何插值。 當達到 KeyTime 時,只會套用新的 值 。 根據要製作動畫的 UI 屬性,這通常會產生看起來「跳躍」的動畫。 確定這是您真正想要的審美行為。 您可以藉由增加宣告的關鍵影格數目來將明顯的跳躍降到最低,但如果平滑的動畫是您的目標,則最好改用線性或雲形線關鍵影格。
備註
離散關鍵影格是使用 DiscreteObjectKeyFrame 為非 Double、Point 和 Color 類型的值製作動畫的唯一方式。 我們將在本主題稍後更詳細地討論這一點。
雲形線關鍵影格
樣條關鍵影格會根據 KeySpline 屬性的值在不同的數值之間創造可變的過渡效果。 此屬性會指定貝塞爾曲線的第一個和第二個控制點,以描述動畫的加速度。 基本上, KeySpline 定義了函數隨時間變化的關係,其中函數時間圖是該貝塞爾曲線的形狀。 您通常會在 XAML 速記屬性字串中指定 KeySpline 值,該值具有四個以空格或逗號分隔的 Double 值。 這些值是貝塞爾曲線的兩個控制點的「X,Y」對。 “X”是時間,“Y”是值的函數修飾符。 每個值都應一律介於 0 到 1 之間,包括 0 和 1。 如果不修改 KeySpline 的控制點,則從 0,0 到 1,1 的直線表示隨時間變化的線性插值函數。 您的控制點會改變該曲線的形狀,從而隨著時間變化改變樣條動畫中函數的行為。 最好將其直觀地視為圖表。
下一個範例顯示三個不同的關鍵幀被應用於動畫,其中最後一個是針對 Double 值的關鍵樣條動畫 (SplineDoubleKeyFrame)。 請注意,針對 KeySpline 套用的字串 「0.6,0.0 0.9,0.00」。 這會產生一條曲線,其中動畫一開始似乎運行緩慢,但隨後在達到 KeyTime 之前快速達到該值。
<Storyboard x:Name="myStoryboard">
<!-- Animate the TranslateTransform's X property
from 0 to 350, then 50,
then 200 over 10 seconds. -->
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="MyAnimatedTranslateTransform"
Storyboard.TargetProperty="X"
Duration="0:0:10" EnableDependentAnimation="True">
<!-- Using a LinearDoubleKeyFrame, the rectangle moves
steadily from its starting position to 500 over
the first 3 seconds. -->
<LinearDoubleKeyFrame Value="500" KeyTime="0:0:3"/>
<!-- Using a DiscreteDoubleKeyFrame, the rectangle suddenly
appears at 400 after the fourth second of the animation. -->
<DiscreteDoubleKeyFrame Value="400" KeyTime="0:0:4"/>
<!-- Using a SplineDoubleKeyFrame, the rectangle moves
back to its starting point. The
animation starts out slowly at first and then speeds up.
This KeyFrame ends after the 6th second. -->
<SplineDoubleKeyFrame KeySpline="0.6,0.0 0.9,0.00" Value="0" KeyTime="0:0:6"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
緩動關鍵幀
緩動關鍵影格是進行插值處理的關鍵影格,而插值隨時間變化的函數是由數個預先定義的數學公式所控制。 實際上,您可以使用樣條關鍵影格產生與某些緩動函數類型大致相同的結果,但也有一些緩動函數,例如 BackEase,是無法用樣條來重現的。
若要將緩動函式套用至緩動關鍵影格,您可以將 EasingFunction 屬性設定為該關鍵影格的 XAML 屬性元素。 針對值,請指定其中一個緩動函數類型的物件元素。
此範例會將 CubicEase 套用,然後將 BounceEase 作為連續的關鍵畫面格套用至 DoubleAnimation ,以建立彈跳效果。
<Storyboard x:Name="myStoryboard">
<DoubleAnimationUsingKeyFrames Duration="0:0:10"
Storyboard.TargetProperty="Height"
Storyboard.TargetName="myEllipse">
<!-- This keyframe animates the ellipse up to the crest
where it slows down and stops. -->
<EasingDoubleKeyFrame Value="-300" KeyTime="00:00:02">
<EasingDoubleKeyFrame.EasingFunction>
<CubicEase/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<!-- This keyframe animates the ellipse back down and makes
it bounce. -->
<EasingDoubleKeyFrame Value="0" KeyTime="00:00:06">
<EasingDoubleKeyFrame.EasingFunction>
<BounceEase Bounces="5"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
這只是一個緩動函數範例。 我們將在下一節中介紹更多內容。
緩動功能
緩動函數可讓您將自訂數學公式套用至動畫。 數學運算通常有助於產生在二維座標系中模擬真實世界物理的動畫。 例如,您可能希望物件真實地彈跳或表現得像在彈簧上一樣。 您可以使用關鍵影格動畫甚至 「From/To/By」 動畫來近似這些效果,但這需要大量的工作,而且相較於使用數學公式,動畫的準確性較低。
緩動函式可以透過三種方式套用至動畫:
- 在關鍵影格動畫中使用緩動關鍵影格,如上一節所述。 使用 EasingColorKeyFrame.EasingFunction、 EasingDoubleKeyFrame.EasingFunction 或 EasingPointKeyFrame.EasingFunction。
- 選擇某個 From// 動畫類型,然後設定其 EasingFunction 屬性。 使用 ColorAnimation.EasingFunction、 DoubleAnimation.EasingFunction 或 PointAnimation.EasingFunction。
- 藉由將 GeneratedEasingFunction 設定為 VisualTransition 的一部分。 這特定於定義控制項的視覺狀態;如需詳細資訊,請參閱 GeneratedEasingFunction 或 視覺狀態的分鏡腳本。
以下是緩動功能的清單:
- BackEase:在動畫開始沿指示的路徑運行之前,稍微縮回。
- BounceEase:建立彈跳效果。
- CircleEase:建立使用循環函數加速或減速的動畫。
- CubicEase:使用公式 f(t) = t3 建立加速或減速的動畫。
- ElasticEase:建立類似彈簧來回擺動直到靜止的動畫。
- ExponentialEase:使用指數公式建立加速或減速的動畫。
- PowerEase:使用公式 f(t) = tp 建立加速或減速的動畫,其中 p 等於 Power 屬性。
- QuadraticEase:使用公式 f(t) = t2 建立加速或減速的動畫。
- QuarticEase:使用公式 f(t) = t4 建立加速或減速的動畫。
- QuinticEase:使用公式 f(t) = t5 建立加速或減速的動畫。
- SineEase:使用正弦公式創建加速或減速的動畫。
部分緩動函式有自己的屬性。 例如, BounceEase 有兩個屬性 Bounces 和 Bounciness ,可修改該特定 BounceEase 的函式隨時間變化行為。 其他緩動函式 ( 例如 CubicEase ) 除了所有緩動函式共用的 EasingMode 屬性之外,沒有其他屬性,而且一律會產生相同的函式隨時間變化行為。
其中一些緩動函數有一些重疊,具體取決於您在具有屬性的緩動函數上設定屬性的方式。 例如,QuadraticEase 與 Power 等於 2 的 PowerEase 完全相同。 而 CircleEase 基本上是預設值 ExponentialEase。
BackEase 緩動函式是獨特的,因為它可以改變超出從/到範圍之外的值,或者是關鍵影格的值。 它會以相反於正常「從/到」行為預期的方向變更值來啟動動畫,再次返回到「從」或「開始」值,然後像平常一樣執行動畫。
在先前的範例中,我們示範如何宣告關鍵影格動畫的緩動函式。 下一個範例會將緩動函式套用至 從/至/依據 動畫。
<StackPanel x:Name="LayoutRoot" Background="White">
<StackPanel.Resources>
<Storyboard x:Name="myStoryboard">
<DoubleAnimation From="30" To="200" Duration="00:00:3"
Storyboard.TargetName="myRectangle"
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
<DoubleAnimation.EasingFunction>
<BounceEase Bounces="2" EasingMode="EaseOut"
Bounciness="2"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</StackPanel.Resources>
<Rectangle x:Name="myRectangle" Fill="Blue" Width="200" Height="30"/>
</StackPanel>
當將緩動函式套用至 從/到/依據 動畫時,它會變更動畫在 持續時間內,值從 從 到 至 的插值隨時間變化的特性。 如果沒有緩動函數,這將是線性插值。
離散物件值動畫
其中一種類型的動畫值得特別提及,因為它是將動畫值套用至非 Double、 Point 或 Color 類型的屬性的唯一方式。 這是關鍵幀動畫 ObjectAnimationUsingKeyFrames。 使用 Object 值進行動畫處理是不同的,因為無法在影格之間插值。 當達到影格的 KeyTime 時,動畫值會立即設定為關鍵影格的 Value 中指定的值。 因為沒有差值計算,因此在ObjectAnimationUsingKeyFrames 的關鍵影格集合中,您只會使用一個關鍵影格: DiscreteObjectKeyFrame。
DiscreteObjectKeyFrame 的 Value 通常會使用屬性元素語法來設定,因為您嘗試設定的物件值通常無法表示為字串來填入屬性語法中的 Value。 如果您使用 StaticResource 等參考,您仍然可以使用屬性語法。
您會看到預設範本中使用的 ObjectAnimationUsingKeyFrames 的其中一個位置是範本屬性參考 Brush 資源時。 這些資源是 SolidColorBrush 物件,而不只是 Color 值,而且它們會使用定義為系統主題的資源 (ThemeDictionaries) 。 它們可以直接指派給 Brush 類型值,例如 TextBlock.Foreground ,而且不需要使用間接目標。 但因為 SolidColorBrush 不是 Double、 Point 或 Color,所以您必須使用 ObjectAnimationUsingKeyFrames 才能使用資源。
<Style x:Key="TextButtonStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Background="Transparent">
<TextBlock x:Name="Text"
Text="{TemplateBinding Content}"/>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationPointerOverForegroundThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationPressedForegroundThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
...
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
您也可以使用 ObjectAnimationUsingKeyFrames 來以動畫方式製作使用列舉值的屬性。 這是來自 Windows 執行階段預設範本的具名樣式的另一個範例。 請注意它如何設定採用 Visibility 列舉常數的 Visibility 屬性。 在此情況下,您可以使用屬性語法來設定值。 您只需要列舉中的非限定常數名稱,即可設定具有列舉值的屬性,例如 “Collapsed”。
<Style x:Key="BackButtonStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="RootGrid">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
... <VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="Collapsed" KeyTime="0"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
...
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
可以為ObjectAnimationUsingKeyFrames框架集使用多個DiscreteObjectKeyFrame。 這可能是藉由動畫化 Image.Source 值來建立「投影片放映」動畫的一個有趣方式,作為多個物件值可能有用的範例。