在WPF開發(fā)應(yīng)用中,動(dòng)畫不僅可以引起用戶的注意與興趣,而且還使軟件更加便于使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關(guān)內(nèi)容,今天繼續(xù)講解動(dòng)畫相關(guān)內(nèi)容和知識點(diǎn),僅供學(xué)習(xí)分享使用,如有不足之處,還請指正。 什么是動(dòng)畫?動(dòng)畫是快速循環(huán)播放一系列圖像(其中每個(gè)圖像與下一個(gè)圖像略微不同)給人造成的一種幻覺。當(dāng)圖像播放速度超過了人眼識別的速度,就會感覺這些圖像形成了一個(gè)連貫的變化的場景。在電影中,攝像機(jī)每秒鐘拍攝許多照片(每一張成為一幀),便可給人造成這種錯(cuò)覺。不同的幀速率會影響視頻的流暢度和清晰度。常見的幀速率包括24幀/秒、25幀/秒、30幀/秒等,這些速率各有其適用場景和特點(diǎn):- ?24幀/秒?:這是電影行業(yè)標(biāo)準(zhǔn)的幀速率,尤其在拍攝無聲電影時(shí)期,24幀/秒被廣泛采用以節(jié)省膠片。盡管如此,24幀/秒在今天仍然被一些藝術(shù)家和獨(dú)立電影制作人使用,以追求特定的視覺效果。
- ?25幀/秒?:適用于PAL制式,主要在歐洲和一些使用50Hz交流電的地區(qū)(如中國)使用。這種幀速率能提供流暢的視頻播放,適用于大多數(shù)日常視頻拍攝。
- ?30幀/秒?:屬于NTSC制式,主要在美國和日本等使用60Hz交流電的地區(qū)使用。30幀/秒提供了與25幀/秒相似的流暢度,但在60Hz的地區(qū)更為常見。
雖然理論上高幀速率(如100幀/秒甚至更高)能提供更流暢的畫面,但在實(shí)際拍攝中,高幀速率的采用受到設(shè)備能力、存儲空間和后期處理成本的限制。因此,在選擇幀速率時(shí),需要綜合考慮技術(shù)可行性、藝術(shù)效果和成本等因素。屬性動(dòng)畫在WPF中,通過對對象的個(gè)別屬性應(yīng)用動(dòng)畫,可以使控件產(chǎn)生動(dòng)畫效果。如:若要使UI元素變大縮小,可以對其Width和Height屬性進(jìn)行動(dòng)畫處理;若要使UI對象從視野中消失或出現(xiàn),可以對Opacity屬性進(jìn)行動(dòng)畫處理。若要使屬性具有動(dòng)畫功能,屬性必須滿足以下三個(gè)要求:
- 屬性必須派生自DependencyObject,并實(shí)現(xiàn)IAnimatable接口類。
由于UIElement類實(shí)現(xiàn)IAnimatable接口,而FramworkElement又派生自UIElement,所以大部分的UI控件都包含IAnimatable屬性的對象。如Button,TabControl,Panel和Shape等,且大多數(shù)屬性都是依賴屬性。如果要實(shí)現(xiàn)一個(gè)Rectangle元素從視野中逐漸消失,然后再次出現(xiàn),并循環(huán)播放,應(yīng)該怎么實(shí)現(xiàn)呢?
- 創(chuàng)建雙精度值動(dòng)畫:首先UI元素從視野中消失的一種方法是對Opacity屬性進(jìn)行動(dòng)畫處理,而Opacity是[0,1]的double類型的值,因此可以創(chuàng)建一個(gè)雙精度值動(dòng)畫(DoubleAnimation)。雙精度值動(dòng)畫主要用戶創(chuàng)建兩個(gè)double類型值之間的轉(zhuǎn)換,可以通過指定DoubleAnimation的起始值(From),終止值(To)。Opacity屬性0表示完全不可見,1表示完全可見。若要使UI元素從不透明到透明的完整過渡,可以設(shè)置DoubleAnimation的From值為1.0,To設(shè)置為0。
- 設(shè)置動(dòng)畫時(shí)長:動(dòng)畫需要在多長的時(shí)間內(nèi)完成,可以通過設(shè)置DoubleAnimation的Duration屬性,Duration屬性在XAML中設(shè)置格式為HH:mm:ss,在C#中Duration接收TimeSpan類型的參數(shù)。
- 設(shè)置動(dòng)畫反向執(zhí)行:動(dòng)畫完成后,是否恢復(fù)初始狀態(tài),可以通過設(shè)置AutoReverse屬性來完成,其中true表示恢復(fù)到初始狀態(tài),false表示停留在結(jié)束狀態(tài)。
- 設(shè)置重復(fù)執(zhí)行:動(dòng)畫是否重復(fù)執(zhí)行,可以通過設(shè)置RepeatBehavior屬性來完成。可指定重復(fù)執(zhí)行的次數(shù),或時(shí)長,如果設(shè)置為Forever,則永久執(zhí)行。
- 創(chuàng)建故事板:動(dòng)畫創(chuàng)建好以后,需要裝填到故事板(Storyboard)并使用TargetName和TargetPropery屬性來指定動(dòng)畫應(yīng)用的目標(biāo)對象和屬性。
- 設(shè)置觸發(fā)事件:通常情況下,可以將開始故事板(BeginStoryboard)與事件觸發(fā)器(EventTrigger)進(jìn)行關(guān)聯(lián)。并添加到EventTrigger的Actions中,并指定RoutedEvent屬性設(shè)置啟動(dòng)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#中實(shí)現(xiàn),如下所示: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;
動(dòng)畫類型不同的屬性值具有不同的動(dòng)畫類型,如果是double類型的屬性(如:width,height,opacity等)進(jìn)行動(dòng)畫處理,則可以使用雙精度動(dòng)畫(DoubleAntmation);如果是Point類似的屬性,則可以使用Point動(dòng)畫(PonitAnimation);如果是顏色類型的屬性,則可以使用ColorAnitmation。這些類型的動(dòng)畫位于System.Windows.Media.Animation命名空間,且都遵循“<類型>Animation”格式的命名約定。具體如下所示:
<類型>Animation,這些動(dòng)畫稱為“From/To/By”或“基本”動(dòng)畫,它們在起始值和目標(biāo)值之間進(jìn)行動(dòng)畫處理,或者通過將偏移量值與其起始值相加來進(jìn)行動(dòng)畫處理。 若要指定起始值,請?jiān)O(shè)置動(dòng)畫的“From”屬性。 若要指定終止值,請?jiān)O(shè)置動(dòng)畫的“To”屬性。 若要指定偏移量值,請?jiān)O(shè)置動(dòng)畫的“By”屬性。
<類型>AnimationUsingKeyFrames,關(guān)鍵幀動(dòng)畫的功能比“From/To/By”動(dòng)畫的功能更強(qiáng)大,因?yàn)榭梢灾付ㄈ我舛鄠€(gè)目標(biāo)值,甚至可以控制它們的插值方法。某些類型只能用關(guān)鍵幀動(dòng)畫進(jìn)行動(dòng)畫處理。 關(guān)鍵幀動(dòng)畫概述中詳細(xì)描述了關(guān)鍵幀動(dòng)畫。 <類型>AnimationUsingPath,路徑動(dòng)畫支持使用幾何路徑來生成動(dòng)畫值。 <類型>AnimationBase,在實(shí)現(xiàn)時(shí)對 <類型> 值進(jìn)行動(dòng)畫處理的抽象類。此類用作 <類型>Animation 和 <類型>AnimationUsingKeyFrames 類的基類。只有在想要?jiǎng)?chuàng)建自己的自定義動(dòng)畫時(shí),才需要直接處理這些類。否則,請使用 <類型>Animation 或 KeyFrame<類型>Animation。
下表顯示了一些常用動(dòng)畫類型以及一些與這些類型一起使用的屬性。 時(shí)間線所有的動(dòng)畫類型均繼承自Timeline類。所以所有的動(dòng)畫都是專用類型的時(shí)間線。Timeline定義一個(gè)時(shí)間段,通過Timeline的相關(guān)屬性,可以指定時(shí)間線的計(jì)時(shí)方式,三個(gè)經(jīng)常使用的計(jì)時(shí)屬性分別為Duration,AutoReverse,和RepeatBehavior。
- Duration表示時(shí)間線完成一次迭代需要的時(shí)間,默認(rèn)值為1秒。Duration的賦值格式為“小時(shí):分鐘:秒”。
- AutoReverse,表示在執(zhí)行一次迭代的時(shí)間線完成后,是否倒退到初始狀態(tài)。如果設(shè)置為true,則將進(jìn)行反向播放動(dòng)畫。默認(rèn)值為false。
- RepeatBehavior,表示事件線的播放次數(shù)。默認(rèn)時(shí)間線的迭代次數(shù)為1次,即動(dòng)畫播放1次,不進(jìn)行重復(fù)。
關(guān)鍵幀動(dòng)畫與From/To/By動(dòng)畫類似,關(guān)鍵幀動(dòng)畫對目標(biāo)類型的屬性進(jìn)行動(dòng)畫處理。它通過Duration值屬性在目標(biāo)值之間創(chuàng)建過渡。但是From/To/By動(dòng)畫可以在兩個(gè)值之間創(chuàng)建過渡,而單個(gè)關(guān)鍵幀動(dòng)畫則可以在任意數(shù)量的目標(biāo)值之間創(chuàng)建過渡。關(guān)鍵幀動(dòng)畫沒有設(shè)置其目標(biāo)值所需要的From,To,By屬性。關(guān)鍵幀動(dòng)畫的目標(biāo)值使用關(guān)鍵幀對象進(jìn)行定義,因此稱之為“關(guān)鍵幀動(dòng)畫”。動(dòng)畫啟動(dòng)后,在各個(gè)關(guān)鍵幀之間進(jìn)行過渡。 關(guān)鍵幀動(dòng)畫創(chuàng)建步驟:- 像From/To/By動(dòng)畫一樣聲明動(dòng)畫,并指定Duration。
- 將每一個(gè)目標(biāo)值創(chuàng)建一個(gè)相應(yīng)類型的關(guān)鍵幀,并設(shè)置值和KeyTime,然后將關(guān)鍵幀添加到KeyFrames集合。
- 將關(guān)鍵幀動(dòng)畫添加到Storyboard,并指定動(dòng)畫對象和屬性。
以下示例使用 DoubleAnimationUsingKeyFrames 對 Rectangle 元素進(jìn)行四個(gè)不同位置的動(dòng)畫處理。<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> 關(guān)鍵幀動(dòng)畫類位于System.Windows.Media.Animation命名空間,且都遵循“<類型>AnimationUsingKeyFrames”格式的命名約定。關(guān)鍵幀動(dòng)畫支持三種不同的插值類型,因此關(guān)鍵幀定義格式遵循如下規(guī)則“<InterpolationMethod><Type>KeyFrame”,其中 <InterpolationMethod> 是關(guān)鍵幀使用的內(nèi)插方法,<Type> 是類進(jìn)行動(dòng)畫處理的值的類型。 例如,可以針對 DoubleAnimationUsingKeyFrames 使用三種關(guān)鍵幀類型:DiscreteDoubleKeyFrame(離散內(nèi)插關(guān)鍵幀)、LinearDoubleKeyFrame(線性內(nèi)插關(guān)鍵幀) 和 SplineDoubleKeyFrame(曲線內(nèi)插關(guān)鍵幀)。 關(guān)鍵幀的主要目的是定義KeyTime和Value值。- Value 屬性指定關(guān)鍵幀的目標(biāo)值。
- KeyTime 屬性指定何時(shí)(在動(dòng)畫的 Duration 內(nèi))到達(dá)關(guān)鍵幀的 Value。
關(guān)鍵幀動(dòng)畫開始后,會按關(guān)鍵幀的 KeyTime 屬性定義的順序來循環(huán)訪問其關(guān)鍵幀。- 如果 0 時(shí)刻沒有關(guān)鍵幀,動(dòng)畫將在目標(biāo)屬性的當(dāng)前值和第一個(gè)關(guān)鍵幀的 Value 之間創(chuàng)建一個(gè)過渡;否則,動(dòng)畫的輸出值將成為第一個(gè)關(guān)鍵幀的值。
- 動(dòng)畫將使用由第二個(gè)關(guān)鍵幀指定的內(nèi)插方法來創(chuàng)建第一個(gè)和第二個(gè)關(guān)鍵幀的 Value 之間的過渡。過渡起始自第一個(gè)關(guān)鍵幀的 KeyTime,在到達(dá)第二個(gè)關(guān)鍵幀的 KeyTime 時(shí)結(jié)束。
- 動(dòng)畫將繼續(xù),這會創(chuàng)建每個(gè)后續(xù)關(guān)鍵幀和其前面的關(guān)鍵幀之間的過渡。
- 最后,該動(dòng)畫過渡到具有最大關(guān)鍵時(shí)間(等于或小于動(dòng)畫的 Duration)的關(guān)鍵幀的值。
注意:KeyTime指定方式可以是“小時(shí):分鐘:秒”的Timespan方式,也可以是百分比方式(該值必須大于或等于 0 并且小于或等于 100%)。路徑動(dòng)畫路徑動(dòng)畫是一種使用PathGeometry作為輸入的動(dòng)畫時(shí)間線(AnimationTimeline),可以定義一個(gè)幾何路徑并使用它來設(shè)置路徑動(dòng)畫的PathGeometry屬性,而不是使用From,To,By屬性或使用關(guān)鍵幀。路徑動(dòng)畫運(yùn)行時(shí),會從路徑中讀取x,y和角度信息并使用該信息生成其輸出。路徑動(dòng)畫對沿著復(fù)雜路徑的對象進(jìn)行動(dòng)畫處理非常有用。不同的屬性值類型,對應(yīng)不同的路徑動(dòng)畫類型。路徑動(dòng)畫類屬于 System.Windows.Media.Animation 命名空間,并使用以下命名約定:其中 <Type> 為該類進(jìn)行動(dòng)畫處理的值的類型。常見的路徑動(dòng)畫如下表所示:- MatrixAnimationUsingPath 從其 PathGeometry 生成 Matrix 值。與 MatrixTransform 一起使用時(shí),MatrixAnimationUsingPath 可以沿路徑移動(dòng)對象。如果將 MatrixAnimationUsingPath 的 DoesRotateWithTangent 屬性設(shè)置為 true,它還會沿路徑曲線旋轉(zhuǎn)對象。
- PointAnimationUsingPath 從其 PathGeometry 的 x 和 y 坐標(biāo)生成 Point 值。通過使用 PointAnimationUsingPath 對采用 Point 值的屬性進(jìn)行動(dòng)畫處理,可以沿路徑移動(dòng)對象。PointAnimationUsingPath 不能旋轉(zhuǎn)對象。
- DoubleAnimationUsingPath 從其 PathGeometry 生成 Double 值。通過設(shè)置 Source 屬性,可以指定 DoubleAnimationUsingPath 是使用 x 坐標(biāo)、y 坐標(biāo)還是路徑的角度作為其輸出??梢允褂?DoubleAnimationUsingPath 來沿著 x 軸或 y 軸旋轉(zhuǎn)或移動(dòng)對象。
以下路徑動(dòng)畫演示了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./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>
參考文檔關(guān)于動(dòng)畫相關(guān)內(nèi)容,可參考官方文檔: https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/graphics-multimedia/animation-overview?view=netframeworkdesktop-4.8以上就是【不可不知的WPF動(dòng)畫(Animation)】的全部內(nèi)容,關(guān)于更多詳細(xì)內(nèi)容,可參考官方文檔。希望能夠一起學(xué)習(xí),共同進(jìn)步。學(xué)習(xí)編程,從關(guān)注【老碼識途】開始,為大家分享更多文章!!!
|