不可不知的WPF動畫(Animation)

老码识途呀發表於2024-09-21

在WPF開發應用中,動畫不僅可以引起使用者的注意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。

什麼是動畫?

動畫是快速迴圈播放一系列影像(其中每個影像與下一個影像略微不同)給人造成的一種幻覺。當影像播放速度超過了人眼識別的速度,就會感覺這些影像形成了一個連貫的變化的場景。在電影中,攝像機每秒鐘拍攝許多照片(每一張成為一幀),便可給人造成這種錯覺。不同的幀速率會影響影片的流暢度和清晰度。常見的幀速率包括24幀/秒、25幀/秒、30幀/秒等,這些速率各有其適用場景和特點:

  • 24幀/秒‌:這是電影行業標準的幀速率,尤其在拍攝無聲電影時期,24幀/秒被廣泛採用以節省膠片。儘管如此,24幀/秒在今天仍然被一些藝術家和獨立電影製作人使用,以追求特定的視覺效果。
  • 25幀/秒‌:適用於PAL制式,主要在歐洲和一些使用50Hz交流電的地區(如中國)使用。這種幀速率能提供流暢的影片播放,適用於大多數日常影片拍攝。
  • 30幀/秒‌:屬於NTSC制式,主要在美國和日本等使用60Hz交流電的地區使用。30幀/秒提供了與25幀/秒相似的流暢度,但在60Hz的地區更為常見。

雖然理論上高幀速率(如100幀/秒甚至更高)能提供更流暢的畫面,但在實際拍攝中,高幀速率的採用受到裝置能力、儲存空間和後期處理成本的限制。因此,在選擇幀速率時,需要綜合考慮技術可行性、藝術效果和成本等因素。

屬性動畫系統

在WPF中,透過對物件的個別屬性應用動畫,可以使控制元件產生動畫效果。如:若要使UI元素變大縮小,可以對其Width和Height屬性進行動畫處理;若要使UI物件從視野中消失或出現,可以對Opacity屬性進行動畫處理。若要使屬性具有動畫功能,屬性必須滿足以下三個要求:

  • 屬性必須是依賴屬性。
  • 屬性必須派生自DependencyObject,並實現IAnimatable介面類。
  • 必須存在可相容的動畫型別。

由於UIElement類實現IAnimatable介面,而FramworkElement又派生自UIElement,所以大部分的UI控制元件都包含IAnimatable屬性的物件。如Button,TabControl,Panel和Shape等,且大多數屬性都是依賴屬性。

屬性動畫

如果要實現一個Rectangle元素從視野中逐漸消失,然後再次出現,並迴圈播放,應該怎麼實現呢?

  • 建立雙精度值動畫:首先UI元素從視野中消失的一種方法是對Opacity屬性進行動畫處理,而Opacity是[0,1]的double型別的值,因此可以建立一個雙精度值動畫(DoubleAnimation)。雙精度值動畫主要使用者建立兩個double型別值之間的轉換,可以透過指定DoubleAnimation的起始值(From),終止值(To)。Opacity屬性0表示完全不可見,1表示完全可見。若要使UI元素從不透明到透明的完整過渡,可以設定DoubleAnimation的From值為1.0,To設定為0。
  • 設定動畫時長:動畫需要在多長的時間內完成,可以透過設定DoubleAnimation的Duration屬性,Duration屬性在XAML中設定格式為HH:mm:ss,在C#中Duration接收TimeSpan型別的引數。
  • 設定動畫反向執行:動畫完成後,是否恢復初始狀態,可以透過設定AutoReverse屬性來完成,其中true表示恢復到初始狀態,false表示停留在結束狀態。
  • 設定重複執行:動畫是否重複執行,可以透過設定RepeatBehavior屬性來完成。可指定重複之行的次數,或時長,如果設定為Forever,則永久執行。
  • 建立故事板:動畫建立好以後,需要裝填到故事板(Storyboard)並使用TargetName和TargetPropery屬性來指定動畫應用的目標物件和屬性。
  • 設定觸發事件:通常情況下,可以將開始故事板(BeginStoryboard)與事件觸發器(EventTrigger)進行關聯。並新增到EventTrigger的Actions中,並指定RoutedEvent屬性設定啟動Storyboard的路由事件。

屬性動畫完整示例如下所示:

<StackPanel Margin="10">
    <Rectangle Name="MyRectangle" Width="100" Height="100" Fill="Blue">
        <Rectangle.Triggers>
            <EventTrigger RoutedEvent="Rectangle.Loaded">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="MyRectangle" Storyboard.TargetProperty="Opacity"
                                         From="1.0" To="0.0" Duration="0:0:5" 
                                         AutoReverse="True" RepeatBehavior="Forever" />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Rectangle.Triggers>
    </Rectangle>
</StackPanel>

上述程式碼在C#中實現,如下所示:

StackPanel panel = new StackPanel();
panel.Margin = new Thickness(10);

Rectangle rectangle = new Rectangle();
rectangle.Name = "rectangle";
this.RegisterName(rectangle.Name, rectangle);
rectangle.Width = 100;
rectangle.Height = 100;
rectangle.Fill = Brushes.Blue;

DoubleAnimation animation = new DoubleAnimation();
animation.From = 1.0;
animation.To = 0.0;
animation.Duration = new Duration(TimeSpan.FromSeconds(5));
animation.AutoReverse = true;
animation.RepeatBehavior = RepeatBehavior.Forever;

var storyboard = new Storyboard();
storyboard.Children.Add(animation);
Storyboard.SetTargetName(animation, rectangle.Name);
Storyboard.SetTargetProperty(animation, new PropertyPath(Rectangle.OpacityProperty));

rectangle.Loaded += new RoutedEventHandler((sender,e) =>{
    storyboard.Begin(this);
});
panel.Children.Add(rectangle);
this.Content = panel;

動畫型別

不同的屬性值具有不同的動畫型別,如果是double型別的屬性(如:width,height,opacity等)進行動畫處理,則可以使用雙精度動畫(DoubleAntmation);如果是Point類似的屬性,則可以使用Point動畫(PonitAnimation);如果是顏色型別的屬性,則可以使用ColorAnitmation。這些型別的動畫位於System.Windows.Media.Animation名稱空間,且都遵循“<型別>Animation”格式的命名約定。具體如下所示:

  • <型別>Animation,這些動畫稱為“From/To/By”或“基本”動畫,它們在起始值和目標值之間進行動畫處理,或者透過將偏移量值與其起始值相加來進行動畫處理。
    • 若要指定起始值,請設定動畫的“From”屬性。

    • 若要指定終止值,請設定動畫的“To”屬性。

    • 若要指定偏移量值,請設定動畫的“By”屬性。

  • <型別>AnimationUsingKeyFrames,關鍵幀動畫的功能比“From/To/By”動畫的功能更強大,因為可以指定任意多個目標值,甚至可以控制它們的插值方法。 某些型別只能用關鍵幀動畫進行動畫處理。 關鍵幀動畫概述中詳細描述了關鍵幀動畫。
  • <型別>AnimationUsingPath,路徑動畫支援使用幾何路徑來生成動畫值。
  • <型別>AnimationBase,在實現時對 <型別> 值進行動畫處理的抽象類。 此類用作 <型別>Animation 和 <型別>AnimationUsingKeyFrames 類的基類。 只有在想要建立自己的自定義動畫時,才需要直接處理這些類。 否則,請使用 <型別>Animation 或 KeyFrame<型別>Animation。

下表顯示了一些常用動畫型別以及一些與這些型別一起使用的屬性。

屬性型別 對應的基本動畫 對應的關鍵幀動畫 對應的路徑動畫 示例
Color ColorAnimation ColorAnimationUsingKeyFrames 對 SolidColorBrush 或 GradientStop 的 Color 進行動畫處理。
Double DoubleAnimation DoubleAnimationUsingKeyFrames DoubleAnimationUsingPath 對 DockPanel 的 Width 或 Button 的 Height 進行動畫處理。
Point PointAnimation PointAnimationUsingKeyFrames PointAnimationUsingPath 對 EllipseGeometry 的 Center 位置進行動畫處理。
String StringAnimationUsingKeyFrames 對 TextBlock 的 Text 或 Button 的 Content 進行動畫處理。

時間線

所有的動畫型別均繼承自Timeline類。所以所有的動畫都是專用型別的時間線。Timeline定義一個時間段,透過Timeline的相關屬性,可以指定時間線的計時方式,三個經常使用的計時屬性分別為Duration,AutoReverse,和RepeatBehavior。

  • Duration表示時間線完成一次迭代需要的時間,預設值為1秒。Duration的賦值格式為“小時:分鐘:秒”。
  • AutoReverse,表示在執行一次迭代的時間線完成後,是否倒退到初始狀態。如果設定為true,則將進行反向播放動畫。預設值為false。
  • RepeatBehavior,表示事件線的播放次數。預設時間線的迭代次數為1次,即動畫播放1次,不進行重複。

關鍵幀動畫

與From/To/By動畫類似,關鍵幀動畫對目標型別的屬性進行動畫處理。它透過Duration值屬性在目標值之間建立過渡。但是From/To/By動畫可以在兩個值之間建立過渡,而單個關鍵幀動畫則可以在任意數量的目標值之間建立過渡。關鍵幀動畫沒有設定其目標值所需要的From,To,By屬性。關鍵幀動畫的目標值使用關鍵幀物件進行定義,因此稱之為“關鍵幀動畫”。動畫啟動後,在各個關鍵幀之間進行過渡。

關鍵幀動畫建立步驟:

  • 像From/To/By動畫一樣宣告動畫,並指定Duration。
  • 將每一個目標值建立一個相應型別的關鍵幀,並設定值和KeyTime,然後將關鍵幀新增到KeyFrames集合。
  • 將關鍵幀動畫新增到Storyboard,並指定動畫物件和屬性。

以下示例使用 DoubleAnimationUsingKeyFrames 對 Rectangle 元素進行四個不同位置的動畫處理。

<Border Width="400" BorderBrush="Black">
    <Rectangle Fill="Blue" Width="50" Height="50" HorizontalAlignment="Left">
        <Rectangle.RenderTransform>
            <TranslateTransform x:Name="MyAnimatedTranslateTransform" X="0" Y="0" />
        </Rectangle.RenderTransform>
        <Rectangle.Triggers>
            <EventTrigger RoutedEvent="Rectangle.MouseLeftButtonDown">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimationUsingKeyFrames Storyboard.TargetName="MyAnimatedTranslateTransform" Storyboard.TargetProperty="X" Duration="0:0:10">
                            <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0" />
                            <LinearDoubleKeyFrame Value="350" KeyTime="0:0:2" />
                            <LinearDoubleKeyFrame Value="50" KeyTime="0:0:7" />
                            <LinearDoubleKeyFrame Value="200" KeyTime="0:0:8" />
                        </DoubleAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Rectangle.Triggers>
    </Rectangle>
</Border>

關鍵幀動畫類位於System.Windows.Media.Animation名稱空間,且都遵循“<型別>AnimationUsingKeyFrames”格式的命名約定。關鍵幀動畫支援三種不同的插值型別,因此關鍵幀定義格式遵循如下規則“<InterpolationMethod><Type>KeyFrame”,其中 <InterpolationMethod> 是關鍵幀使用的內插方法,<Type> 是類進行動畫處理的值的型別。 例如,可以針對 DoubleAnimationUsingKeyFrames 使用三種關鍵幀型別:DiscreteDoubleKeyFrame(離散內插關鍵幀)、LinearDoubleKeyFrame(線性內插關鍵幀) 和 SplineDoubleKeyFrame(曲線內插關鍵幀)。

關鍵幀的主要目的是定義KeyTime和Value值。

  • Value 屬性指定關鍵幀的目標值。

  • KeyTime 屬性指定何時(在動畫的 Duration 內)到達關鍵幀的 Value。

關鍵幀動畫開始後,會按關鍵幀的 KeyTime 屬性定義的順序來迴圈訪問其關鍵幀。

  • 如果 0 時刻沒有關鍵幀,動畫將在目標屬性的當前值和第一個關鍵幀的 Value 之間建立一個過渡;否則,動畫的輸出值將成為第一個關鍵幀的值。

  • 動畫將使用由第二個關鍵幀指定的內插方法來建立第一個和第二個關鍵幀的 Value 之間的過渡。 過渡起始自第一個關鍵幀的 KeyTime,在到達第二個關鍵幀的 KeyTime 時結束。

  • 動畫將繼續,這會建立每個後續關鍵幀和其前面的關鍵幀之間的過渡。

  • 最後,該動畫過渡到具有最大關鍵時間(等於或小於動畫的 Duration)的關鍵幀的值。

注意:KeyTime指定方式可以是“小時:分鐘:秒”的Timespan方式,也可以是百分比方式(該值必須大於或等於 0 並且小於或等於 100%)。

路徑動畫

路徑動畫是一種使用PathGeometry作為輸入的動畫時間線(AnimationTimeline),可以定義一個幾何路徑並使用它來設定路徑動畫的PathGeometry屬性,而不是使用From,To,By屬性或使用關鍵幀。路徑動畫執行時,會從路徑中讀取x,y和角度資訊並使用該資訊生成其輸出。路徑動畫對沿著複雜路徑的物件進行動畫處理非常有用。不同的屬性值型別,對應不同的路徑動畫型別。

路徑動畫類屬於 System.Windows.Media.Animation 名稱空間,並使用以下命名約定:

<Type>AnimationUsingPath

其中 <Type> 為該類進行動畫處理的值的型別。常見的路徑動畫如下表所示:

屬性型別 相應的路徑動畫 說明
Double DoubleAnimationUsingPath 沿著路徑進行動畫處理(雙重動畫)
Matrix MatrixAnimationUsingPath 沿著路徑進行動畫處理(矩陣動畫)
Point PointAnimationUsingPath 沿著路徑進行動畫處理(點動畫)

路徑動畫說明:

  • MatrixAnimationUsingPath 從其 PathGeometry 生成 Matrix 值。 與 MatrixTransform 一起使用時,MatrixAnimationUsingPath 可以沿路徑移動物件。 如果將 MatrixAnimationUsingPath 的 DoesRotateWithTangent 屬性設定為 true,它還會沿路徑曲線旋轉物件。
  • PointAnimationUsingPath 從其 PathGeometry 的 x 和 y 座標生成 Point 值。 透過使用 PointAnimationUsingPath 對採用 Point 值的屬性進行動畫處理,可以沿路徑移動物件。 PointAnimationUsingPath 不能旋轉物件。
  • DoubleAnimationUsingPath 從其 PathGeometry 生成 Double 值。 透過設定 Source 屬性,可以指定 DoubleAnimationUsingPath 是使用 x 座標、y 座標還是路徑的角度作為其輸出。 可以使用 DoubleAnimationUsingPath 來沿著 x 軸或 y 軸旋轉或移動物件。

以下路徑動畫演示了MatrixAnimationUsingPath 的使用方式:

<Window x:Class="WpfApp5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp5"
        xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Canvas Width="400" Height="400">
        <Button MinWidth="100" Content="A Button">
            <Button.RenderTransform>
                <MatrixTransform x:Name="ButtonMatrixTransform">
                    <MatrixTransform.Matrix >
                        <Matrix />
                    </MatrixTransform.Matrix>
                </MatrixTransform>
            </Button.RenderTransform>
            <Button.Triggers>
                <EventTrigger RoutedEvent="Button.Loaded">
                    <BeginStoryboard>
                        <Storyboard>
                            <MatrixAnimationUsingPath Storyboard.TargetName="ButtonMatrixTransform"
                                                      Storyboard.TargetProperty="Matrix"
                                                      DoesRotateWithTangent="True"
                                                      Duration="0:0:5" 
                                                      RepeatBehavior="Forever" >
                                <MatrixAnimationUsingPath.PathGeometry>
                                    <PathGeometry Figures="M 10,100 C 35,0 135,0 160,100 180,190 285,200 310,100" 
                                                  PresentationOptions:Freeze="True" />
                                </MatrixAnimationUsingPath.PathGeometry>
                            </MatrixAnimationUsingPath>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Button.Triggers>
        </Button>
    </Canvas>
</Window>

關於動畫相關內容,可參考官方文件:

https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/graphics-multimedia/animation-overview?view=netframeworkdesktop-4.8

以上就是《不可不知的WPF動畫(Animation)》的全部內容,希望可以拋磚引玉,一起學習,共同進步!!!

相關文章