之前的總結
動畫部分的內容比較多,會分幾個部分總結,年后會分享高級動畫部分,2019年希望能養成寫博客總結的好習慣,還有之前在印象筆記中總結的東西也陸續寫到博客中,感興趣的小伙伴可以關注下,希望對你有所幫助!
理解WPF動畫
在許多用戶框架中,開發人員必須從頭構建自己的動畫系統。最常用的技術是結合使用計時器和一些自定義的繪圖邏輯。WPF通過自帶的基於屬性的動畫系統,改變了這種狀況。
基於時間的動畫
例如需要旋轉Windows窗體應用程序中的About對話框中的一塊文本。下面是構建改解決方案的傳統方法。
- 創建周期性觸發的計時器。
- 當觸發器出發時,使用事件處理程序計算一些與動畫相關的細節,如新的旋轉角度。然后使窗口的一部分或整個窗口無效。
- 不久后,Windows將要求窗口重新繪制自身,觸發自定義的繪圖代碼。
- 在自定義繪圖代碼中,渲染旋轉后的文本。
盡管整個基於計時器的解決方案不難實現。但將它集成到普通的應用程序窗口中卻非常麻煩,存在如下問題
- 繪制像素而不是控件。為選擇Windows窗體中的文本,需要低級的GDI+繪圖支持。GDI+易於使用,但卻不能與普通的窗口元素很好的相互協調。
- 假定單一動畫。如果需要運行兩個動畫。就需要重新編寫所有動畫代碼,變得更復雜。
- 動畫幀率是固定的。計時器決定了幀率,想修改,還可能修改代碼。
- 復雜動畫需要指數級增長的更復雜的代碼。
基於屬性的動畫
WPF提供了一個更高級的模型,通過該模型可以只關注動畫的定義,而不必考慮他們的渲染方式。這個模型基於依賴項屬性基礎架構。本質上,WPF動畫只不過是在一段時間間隔內修改依賴項屬性值的一種方式。
例如,為了增大和縮小按鈕,可在動畫中修改按鈕的寬度。為使按鈕閃爍,可修改用於按鈕背景的LinearGradientBrush屬性。創建動畫的秘密在於決定需要修改什么樣的屬性。
Animotion類
動畫種類,在System.Windows.Media.Animation名稱控件中將發現以下內容。
- 17個“類型名+Animation”類,這些類使用插值。(在開始值和結束值之間以逐步增加的方式。)
- 22個“類型名+AnimationUsingKeyFrames”類,這些類使用關鍵幀動畫。(從一個值突然變成另一個值。)
- 3個“類型名+AnimationUsingPath”類,這些類使用基於路徑的動畫。
使用代碼創建動畫
<Grid> <Button Name="btnShow" Width="300" Height="50" VerticalAlignment="Center" HorizontalAlignment="Center" Click="Button_Click"> <Button.Background> <LinearGradientBrush> <GradientStop Color="Red" Offset="0"></GradientStop> <GradientStop Color="Blue" Offset="0.5"></GradientStop> </LinearGradientBrush> </Button.Background> Click and Make Me Show</Button> </Grid>
DoubleAnimation withAnimation = new DoubleAnimation(); withAnimation.From =btnShow.ActualWidth; withAnimation.To = this.Width - 30; withAnimation.Duration = TimeSpan.FromSeconds(5); btnShow.BeginAnimation(Button.WidthProperty, withAnimation);


1.From屬性
Form值是Width屬性的開始值。如果多次單擊按鈕,每次單擊的時,都會將Width屬性重新設置為160.並且重新開始運行動畫。
在許多情況下可能不希望動畫從最初的From值開始。有兩個常見的原因。
-
創建能夠被觸發多次,並逐次累加的動畫效果。例如,可能希望創建每次點擊都增大一點的按鈕。
-
創建可能相互重疊的動畫。例如,可使用MouseEnter事件觸發擴展按鈕的動畫,並使用MouseLeave事件觸發將按鈕縮小為原尺寸的互補動畫(這通常稱為"魚眼"效果)。
如上面的效果可以不指定初始值。
DoubleAnimation withAnimation = new DoubleAnimation(); withAnimation.To = this.Width - 30; withAnimation.Duration = TimeSpan.FromSeconds(5); btnShow.BeginAnimation(Button.WidthProperty, withAnimation);
ActualWidth和Width屬性的區別,Width屬性反應的是選擇的期望寬度,而AcutalWidth值指示的是最終使用的渲染寬度。如果使用自動布局,可能根本就沒有設置硬編碼的Width值,所Width屬性只會返回Double.NaN值,開始動畫時會拋異常。
2.To屬性
就像可省略From屬性一樣也可省略To屬性。
3.By屬性
By屬性用於創建按鈕設置的數量改變值的動畫,而不是目標改變值。
DoubleAnimation withAnimation = new DoubleAnimation(); withAnimation.By = 10; withAnimation.Duration = TimeSpan.FromSeconds(5); btnShow.BeginAnimation(Button.WidthProperty, withAnimation);
4.Duration屬性
在動畫開始時刻和結束時刻之間的時間間隔。
Timeline類
動畫類繼承自Timeline抽象類,有三個主要子類,播放音頻或視頻文件時使用的MediaTimeline類,基於屬性的AnimationTimeline類,允許同步時間線並控制他們的播放速度的TimelineGroup類。
Timeline類屬性
名稱
|
說明
|
BeginTime | 設置被添加到動畫開始之前的延遲時間(TimeSpan類型)。這一延遲被加到總時間,所以具有5秒延遲的5秒動畫,總時間是10秒。當按順序應用效果不同的動畫時,BeginTime屬性是很有用的。 |
Duration | 使用Duration對象設置動畫從開始到結束的時間。 |
SpeedRadio | 提高或減慢動畫速度。通常,SpeedRadio屬性值是1。如果增加該屬性值,動畫會加快(例如,如果SpeedRadio屬性的值為5,動畫的速度會變為原來的5倍);如果減小該屬性的值,動畫會變慢。可通過改變動畫的Duration屬性值得到相同的結果。當應用BeginTime延遲時,不考慮SpeedRadio屬性的值。 |
AccelerationRadio
DecelerationRadio
|
使動畫不是線性的,從開始時較慢,然后增速(通過增加AccelarationRadio屬性值);或者結束時降低速度(通過增加Decelaration屬性值。)這兩個值都在0到1之間。初始值都是0. |
AutoReverse | 如果為True,當動畫完成時會自動反向播放,返回到原始值。這也會使動畫的運行時間加倍。如果增加SpeedRatio屬性值,就會應用到最初的動畫播放以及反向的動畫播放。BeginTime屬性值只應用於動畫的開始-不延遲反向動畫。 |
FillBehavior | 決定當動畫結束時如何操作。通常,可將屬性值保持為固定的結算值(FillBehavior.HoldEnd),但是也可以選擇將屬性值返回原來的數值(FillBehavior.Stop) |
RepeatBehavior | 通過該屬性,可以使用指定的次數或時間間隔重復動畫。 |
withAnimation.RepeatBehavior = new RepeatBehavior(3);//重復3個
withAnimation.RepeatBehavior = new RepeatBehavior(TimeSpan.FromSeconds(13));//重復13秒
withAnimation.RepeatBehavior = RepeatBehavior.Forever;//一直重復
故事板
WPF動畫使用了極少數的屬性設置信息,如開始值、結束值以及持續時間。非常適合於XAML。不是很清晰的是如何為特定的事件和屬性關聯動畫,以及如何在正確的時間觸發動畫。
在所有聲明式動畫中都會用到如下兩個要素:
-
故事板。故事板是BeginAnimation()方法的XAML等價物。通過故事板將動畫指定到合適的元素和屬性。
-
事件觸發器。時間觸發器相應屬性變化或事件,並控制故事板。
故事板是增強的時間線,可用來分組多個動畫,具有控制動畫播放的能力,暫停、停止以及改變播放位置。通過TargetProperty和TargetName屬性值指向某個元素和特定屬性。
<Button Padding="10" Name="cmdGrow" Height="40" Width="160" HorizontalAlignment="Center" VerticalAlignment="Center"> <Button.Triggers> <EventTrigger RoutedEvent="Button.Click"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation AutoReverse="True" Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Width" Duration="0:0:5" To=" 300"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Button.Triggers> <Button.Content> Click Me And Make Me Grow </Button.Content> </Button>
Storyboard.TargetProperty 如果沒有提供類的名稱,故事板使用父元素。如果希望設置附加屬性,用如下語法。
Storyboard.TargetProperty="(Canvas.Left)"
樣式觸發器
<Window.Resources> <Style x:Key="GrowButtonStyle"> <Style.Triggers> <Trigger Property="Button.IsPressed" Value="True"> <Trigger.EnterActions> <BeginStoryboard> <Storyboard> <DoubleAnimation AutoReverse="True" Storyboard.TargetProperty="Width" Duration="0:0:5" To=" 300"></DoubleAnimation> </Storyboard> </BeginStoryboard> </Trigger.EnterActions> </Trigger> </Style.Triggers> </Style> </Window.Resources> <Grid> <Button Padding="10" Style="{StaticResource GrowButtonStyle}" Name="cmdGrow" Height="40" Width="160" HorizontalAlignment="Center" VerticalAlignment="Center"> <Button.Content> Click Me And Make Me Grow </Button.Content> </Button> </Grid> </Window>
同步的動畫
<EventTrigger RoutedEvent="Button.Click"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation AutoReverse="True" Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Width" Duration="0:0:5" To=" 300"></DoubleAnimation> <DoubleAnimation AutoReverse="True" Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Height" Duration="0:0:5" To=" 300"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger>
控制播放
一旦創建故事板,就可以用其他動作控制故事板。這些動作都繼承自ControllableStoryboardAction類。
名稱
|
說明
|
PauseStoryboard | 停止播放動畫並且保持其當前位置。 |
ResumeStroyboard | 恢復播放暫停的動畫。 |
StopStoryboard | 停止播放動畫,並將動畫時鍾重新設置到開始位置。 |
SeekStoryboard | 跳到動畫線中的特定位置。如果動畫正在播放,就繼續從新位置播放。如果動畫是暫停的,就繼續保持暫停。 |
SetStoryboardSpeedRadio | 改變整個故事板的SpeedRatio屬性值。 |
SkipStoryboardToFill | 講故事板移到時間線的終點。 |
RemoveStoryboard | 移除故事板,停止所有在運行的動畫並將屬性返回原來的、最后一次設置的值。 |
白天過度到黑夜動畫效果


<Window.Triggers> <EventTrigger SourceName="cmdStart" RoutedEvent="Button.Click"> <BeginStoryboard Name="fadeStoryboardBegin"> <Storyboard> <DoubleAnimation Storyboard.TargetName="imgDay" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:10"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger> <EventTrigger SourceName="cmdPause" RoutedEvent="Button.Click"> <PauseStoryboard BeginStoryboardName="fadeStoryboardBegin"></PauseStoryboard> </EventTrigger> <EventTrigger SourceName="cmdResume" RoutedEvent="Button.Click"> <RemoveStoryboard BeginStoryboardName="fadeStoryboardBegin"></RemoveStoryboard> </EventTrigger> <EventTrigger SourceName="cmdStop" RoutedEvent="Button.Click"> <StopStoryboard BeginStoryboardName="fadeStoryboardBegin"></StopStoryboard> </EventTrigger> <EventTrigger SourceName="cmdMiddle" RoutedEvent="Button.Click"> <SeekStoryboard BeginStoryboardName="fadeStoryboardBegin" Offset="0:0:5"></SeekStoryboard> </EventTrigger> </Window.Triggers> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"></RowDefinition> <RowDefinition Height="60"></RowDefinition> </Grid.RowDefinitions> <Image Source="http://pic28.photophoto.cn/20130805/0034034811466737_b.jpg"></Image> <Image Source="http://img.pconline.com.cn/images/upload/upc/tx/itbbs/1608/11/c3/25402170_1470872089662_mthumb.jpg" Name="imgDay"></Image> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="5" Grid.Row="1" Height="60"> <Button Name="cmdStart" Height="20" Width="50">Start</Button> <Button Name="cmdPause" Height="20" Width="50">Pause</Button> <Button Name="cmdResume" Height="20" Width="50">Resume</Button> <Button Name="cmdStop" Height="20" Width="50">Stop</Button> <Button Name="cmdMiddle" Height="20" Width="50">Move To Middle</Button> </StackPanel> </Grid>