1、基本動畫。
WPF提供了一個更高級的模型,通過該模型可以只關注動畫的定義,而不考慮它們的渲染方式,這個模型基於依賴項屬性基礎架構,本質上,WPF動畫只不過是在一段時間間隔內修改依賴項屬性值的一種方式。不過還有另外一個限制,為了實現屬性的動態化,需要有支持相應數據類型的動畫類,例如Button.Width屬性使用雙精度數據類型,為實現屬性的動態化,需要使用DoubleAnimation類,但Button.Padding屬性使用的是Thickness結構,所以需要使用ThicknessAnimation類。為了為屬性應用動畫,可以針對相應的數據類型創建自己的動畫類,你將發現,System.Windows.Media.Animation名稱空間已經為希望使用的大多數數據類型提供了動畫類。
2、Animation類。
實際上有兩種類型的動畫,一種是在開始值和結束值之間以逐步增加的方式改變屬性的動畫(線性插值過程),另一種是從一個值突然變成另一值得動畫(關鍵幀動畫)。所有關鍵幀動畫都使用 "類型名 + AnimationUsingKeyFrames " 的形式進行命名,比如StringAnimationUsingKeyFrames和ObjectAnimationUsingKeyFrames。某些數據類型有關鍵幀動畫類,但沒有插值動畫類。例如,可使用關鍵幀為字符串應用動畫,不能使用插值為字符串應用動畫。然而,所有數據類型都支持關鍵幀動畫,除非他們根本不支持動畫。所有具有(使用插值)常規動畫類的數據類型,也都有相應的關鍵幀動畫的動畫類型,如線性插值的DoubleAnimation對應DoubleAnimationUsingKyyFrames。另外還有一種基於路徑的動畫。因此,WPF動畫使用三種方法:線性插值、關鍵幀和路徑。在System.Windows.Media.Animation名稱空間中將發現以下內容:
7個 "類型名+Animation類" 這些類使用插值動畫。
22個 "類型名+AnimationUsingKeyFrames" 這些類使用關鍵幀動畫。
3個 "類型名+AnimationUsingPath"類這類使用基於路徑的動畫。
3、使用代碼創建動畫。
wpf中,最常用的動畫技術是線性插值動畫,標准的幀速率是60秒/幀,使用動畫的最簡單方式是實例化在前面列出的其中一個動畫類,然后使用修改元素的BeginAnimation()方法,所有wpf元素,從UIElement基類開始,都繼承了BeginAnimation()方法,該方法是IAnimatable接口的一部分。
xaml代碼:
<Button Width="150" Height="60" Grid.Row="0" Click="Button_Click">點擊開始動畫</Button>
<Button Grid.Row="1" Name="btn1" Width="150" Height="60" Content="動畫按鈕"></Button>
后台代碼:
private void Button_Click(object sender, RoutedEventArgs e) { //實例化一個DoubleAnimation類。
DoubleAnimation doubleAnimation = new DoubleAnimation(); //設置From屬性。
doubleAnimation.From = btn1.Width; //設置To屬性。
doubleAnimation.To = 250; //設置Duration屬性。
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5)); //為元素設置BeginAnimation方法。
btn1.BeginAnimation(Button.WidthProperty, doubleAnimation); }
效果圖:
其中, From屬性是元素的開始值,To屬性是元素屬性的結束值,Duration是整個動畫執行的時間。即使不使用To屬性,也可以使用By屬性,By值被簡單地增加到From值上,使其達到To值。不過,對於非數值數據類型來說,By屬性是沒有意義的。
4、同時發生的動畫。
就是創建多個Animation動畫,然后為元素設置屬性。
后台代碼:
private void Button_Click(object sender, RoutedEventArgs e) { //實例化一個DoubleAnimation類。
DoubleAnimation doubleAnimation = new DoubleAnimation(); //設置From屬性。
doubleAnimation.From = btn1.Width; //設置To屬性。
doubleAnimation.To = 250; //設置Duration屬性。
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5)); //為元素設置BeginAnimation方法。
btn1.BeginAnimation(Button.WidthProperty, doubleAnimation); //實例化一個DoubleAnimation動畫,用於設置元素的高。
DoubleAnimation doubleAnimationHeight = new DoubleAnimation(); //設置Form屬性。
doubleAnimationHeight.From = btn1.Height; //設置To屬性的值。
doubleAnimationHeight.By = 70; //設置時間。
doubleAnimationHeight.Duration = new Duration(TimeSpan.FromSeconds(3)); //開始動畫。
btn1.BeginAnimation(Button.HeightProperty, doubleAnimationHeight); }
5、動畫的生命周期。
從技術的角度看,WPF動畫只是暫時的,這意味着它們不能真正改變基本屬性的值,當動畫處於活動狀態時,只是覆蓋了屬性的值。
單向動畫,在動畫運行結束后會保持處於活動狀態,這是因為動畫需要將按鈕的寬度保持為新值,這回導致如下常見問題,如果嘗試使用代碼在動畫完成后修改屬性值,代碼將不會起作用,因為代碼只是為屬性指定了一個新的本地值,但仍會先試用動畫之后的屬性值。
為了解決動畫完成后能修改屬性的值,有以下方法可解決。
a)、設置AutoReverse屬性,如果將該屬性設置為true,將會反向運動,返回原始的值(不適合動畫完成后,再為屬性設置最后的值,只是還原為動畫之前的值)。
b)、改變FillBehavior屬性。通常,FillBehavior屬性設置為HoldEnd,這意味着當當動畫結束時,會繼續為目標元素應用最后的值。如果將FillBehavior屬性改為Stop,只要動畫結束,屬性就會恢復為原來的值(適用於動畫結束后,再次為其設置新值,一般不與AutoReverse配合着使用,這兩個用其中一個就行了)。
6、動畫的Completed事件。
使用Completed事件時,要將事件設置BeginAnimation()方法之前,否則不起作用。在Completed中,可通過調用BeginAnimation()方法來渲染不活動的動畫,為此,只需要指定屬性,並為動畫對象傳遞null引用。
void doubleAnimationHeight_Completed(object sender, EventArgs e) { MessageBox.Show("動畫的高執行完畢了!!!"); //設置空引用。
btn1.BeginAnimation(Button.HeightProperty, null); }
7、TimeLine類。
TimeLine類的常用屬性。
TimeLine類的常用屬性 | |
名稱 | 說明 |
BeginTime | 設置將被添加到動畫開始之前的延時時間(TimeSpan類型),這一延時總被加載到總時間,具有5秒延時的5秒動畫,總時間是10秒。 |
Duration | 動畫開始到結束的運行時間。 |
SpeedRatio | 提高或減慢動畫速度。SpeedRatio屬性值是1,如果增加該屬性值為5,動畫的速度就會變成原來的5倍。 |
AcclerationRatio |
使動畫不是線性的,從而開始時較慢,或者開始時較快,這兩個屬性的值都在0~1之間,這兩個屬性值之和不能超過1。 |
AutoReverse | 如果為true,當動畫完成時會自動反向播放,返回到原始值。 |
FillBehavior | 決定當動畫結束時,如何操作。 |
RepeatBehavior | 通過該屬性,可以使用指定的次數或時間間隔重復動畫,用於設置這個屬性的RepeatBehavior對象決定了確切的行為。 |
7.1)、AccelerationRatio和DeceleRation屬性。
可以通過AcclerationRation和DecelerationRation屬性壓縮部分時間軸,使動畫運行的更快,並將拉伸其他時間進行補償,使總時間保持不變。這兩個屬性都表示百分比值,例如,將AcceleRation屬性設置為0.3,表示希望使用動畫持續時間中前30%的時間進行加速。例如在1個10秒的動畫中,前3秒會加速運行,而剩余的7秒會以恆定不變的速度運行,如果將DeceleRation屬性設置為0.3,那么最后3秒回減速運行。
private void Button_Click(object sender, RoutedEventArgs e) { //實例化一個DoubleAnimation類。
DoubleAnimation doubleAnimation = new DoubleAnimation(); //設置From屬性。
doubleAnimation.From = btn1.Width; //前5秒加速度運行。
doubleAnimation.AccelerationRatio = 0.5; //后2秒減速運行
doubleAnimation.DecelerationRatio = 0.2; //設置To屬性。
doubleAnimation.To = 1000; //設置Duration屬性。
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(10)); //為元素設置BeginAnimation方法。
btn1.BeginAnimation(Button.WidthProperty, doubleAnimation); }
7.2)、RepeatBehavior屬性。
使用RepeataBehavior屬性可以控制如何重復運行動畫,如果希望重復固定次數,應為RepeatBehavior構造函數傳遞合適的次數。
還可設置RepeatBehavior為永久重復。
//設置重復次數為3次。
doubleAnimation.RepeatBehavior = new RepeatBehavior(3); //設置永久重復動畫。
doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
8、故事版。
WPF動畫通過一組動畫類表示,使用少數幾個屬性設置相關信息,如開始值、結束值以及持續時間。這顯然使他們非常適合於XAMl,不是很清晰的是,如何為特定的事件和屬性關聯動畫,以及如何在正確的時間觸發動畫。
故事板:故事板是BeginAnimation()方法的XAML等價物,通過故事板將動畫指定到合適的元素和屬性。
事件觸發器:事件觸發器響應屬性變化或事件(如按鈕的Click事件),並控制故事板。
故事板:
故事板是增強的時間線,可用來分組多個動畫,而且具有控制動畫播放的能力---暫停、停止以及播放位置。然而Storyboard類提供的最基本功能是,能夠使用TargetProperty和TargetName屬性指向某個特定屬性和特定元素,換句話說,故事板在動畫和希望應用動畫的屬性之間架起了一座橋梁。其中TargetProperty屬性和TargetName屬性都是附加屬性。
<!--創建一個故事板-->
<Storyboard Storyboard.TargetProperty="Width">
<!--創建一個DoubleAnimation類。-->
<DoubleAnimation To="350" RepeatBehavior="Forever" Duration="0:0:3"></DoubleAnimation>
</Storyboard>
<!--由於Storyboard.TargetProperty屬性是附加屬性,因此還可以寫出-->
<Storyboard >
<!--創建一個DoubleAnimation類。-->
<DoubleAnimation Storyboard.TargetProperty = "Width" To="350" RepeatBehavior="Forever" Duration="0:0:3"></DoubleAnimation>
</Storyboard>
事件觸發器:
可以在以下4個位置定義事件觸發器。
a)、在樣式中(Style.Triggers集合)。
b)、在數據模板中(DataTemplate.Triggers集合)。
c)、在控件模板中(ControlTemplate.Triggers集合)。
d)、直接在元素中定義事件觸發器(FrameworkElement.Triggers集合)。
當創建事件觸發器時,需要指定開始觸發器的路由事件和觸發器執行的一個或多個動作。對於動畫,最常用的動作是BeginStoryboard,該動作相當於調用BeginAnimation()方法。所有事件觸發器都可以啟動動作,所有動作都由繼承自System.Windows.TriggerAction的類表示。
xaml代碼:
<Button Width="200" Height="80" Content="事件觸發器" FontSize="20">
<!--元素觸發器-->
<Button.Triggers>
<!--定義事件觸發器-->
<EventTrigger RoutedEvent="Button.Click">
<!--執行一個動作-->
<EventTrigger.Actions>
<!--開始故事板-->
<BeginStoryboard>
<!--創建一個故事板-->
<Storyboard >
<!--創建一個DoubleAnimation類。-->
<DoubleAnimation Storyboard.TargetProperty = "Width" To="350" RepeatBehavior="Forever" Duration="0:0:3"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
效果圖:
9、使用樣式關聯觸發器。
有三種基本類型的WPF觸發器:屬性觸發器、數據觸發器以及事件觸發器。使用觸發器是關聯動畫的最常用方式,但並不是唯一的選擇。
xaml代碼:
<Window.Resources>
<Style TargetType="Button">
<Setter Property="FontSize" Value="20"></Setter>
<Style.Triggers>
<!--使用屬性觸發器-->
<Trigger Property="IsPressed" Value="True">
<!--在這里使用的是EnterActions-->
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="Width">
<DoubleAnimation To="300" RepeatBehavior="Forever" Duration="0:0:3"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style>
</Window.Resources>
<Grid>
<Button Width="200" Height="80" Content="使用樣式關聯觸發器"></Button>
</Grid>
效果圖:
10、同步的動畫。
StoryBoard類間接地繼承自TimeLineGroup類,所以StoryBoard類能包含多個動畫,這些動畫可以作為一組進行管理,這意味着它們可以在同一時間開始。
<Window.Resources>
<Style TargetType="Button">
<Setter Property="FontSize" Value="20"></Setter>
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" To="300" Duration="0:0:3"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="Height" To="100" Duration="0:0:3"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Button Width="150" Height="70" Content="同步動畫"></Button>
</Grid>
效果圖:
11、控制播放。
到目前為止,已經在事件觸發器中使用了一個動作,加載動畫的BeginStoryboard動作,然而,一旦創建故事版,就可以使用其他動作控制故事板,這些動作類都繼承自ControllableStoryboardAction類,控制故事版的主要類如下:
控制故事板的動作類 | |
名稱 | 說明 |
PauseStoryboard | 停止播放動畫並且保持當前位置 |
ResumeStoryboard | 恢復播放暫停的動畫。 |
StopStoryboard | 停止播放動畫,並將動畫時鍾重新設置到開始位置。 |
SeekStoryboard | 跳到動畫時間線中的特定位置,如果當前動畫正在播放,就繼續從新位置播放。如果當前動畫 |
SetStoryboardSpeedRatio | 改變整個故事板的SpeedRatio屬性值。 |
SkipStoryboardToFill | 將故事板移動到時間線的終點。FillBehavior屬性設置為HoldEnd,動畫繼續保持最后的值。 |
RemoveStoryboard | 移除故事板,停止所有正在運行的動畫,並將屬性返回為原來的、最后一次設置的數值。 |
為成功地執行這些動作,必須在同一個Triggers集合中定義所有的觸發器,如果將BeginStoryboard動作的觸發器和PauseStoryboard動作的觸發器放置到不同的集合中,PauseStoryboard動作就無法工作。
xaml代碼:
<Window x:Class="控制播放.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525">
<Window.Triggers>
<!--開始事件-->
<EventTrigger RoutedEvent="Button.Click" SourceName="btn_start">
<BeginStoryboard Name="beginstoryboard1">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="img" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:6"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<!--停止動畫-->
<EventTrigger RoutedEvent="Button.Click" SourceName="btn_pause">
<PauseStoryboard BeginStoryboardName="beginstoryboard1"></PauseStoryboard>
</EventTrigger>
<!--恢復動畫-->
<EventTrigger RoutedEvent="Button.Click" SourceName="btn_resume">
<ResumeStoryboard BeginStoryboardName="beginstoryboard1"></ResumeStoryboard>
</EventTrigger>
<!--停止動畫-->
<EventTrigger RoutedEvent="Button.Click" SourceName="btn_stop">
<StopStoryboard BeginStoryboardName="beginstoryboard1"></StopStoryboard>
</EventTrigger>
<!--移除動畫-->
<EventTrigger RoutedEvent="Button.Click" SourceName="btn_remove">
<RemoveStoryboard BeginStoryboardName="beginstoryboard1"></RemoveStoryboard>
</EventTrigger>
</Window.Triggers>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="3*"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Image Name="img" Source="1.jpg"></Image>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Name="btn_start" Content="開始" Margin="10" FontSize="20" Grid.Column="0"></Button>
<Button Name="btn_pause" Content="暫停" Margin="10" FontSize="20" Grid.Column="1"></Button>
<Button Name="btn_resume" Content="恢復" Margin="10" FontSize="20" Grid.Column="2"></Button>
<Button Name="btn_stop" Content="停止" Margin="10" FontSize="20" Grid.Column="3"></Button>
<Button Name="btn_remove" Content="移除" Margin="10" FontSize="20" Grid.Column="4"></Button>
</Grid>
</Grid>
</Window>
效果圖:
分析:在包含元素的Triggers集合中(在這里是Window.Triggers集合),使用EventTrigger.SourceName屬性關聯這些事件觸發器,只要SourceName屬性和為按鈕設置的Name屬性相匹配,觸發器就會用到恰當的按鈕上。還必須要問BeginStoryboard動作指定名稱,這樣其他觸發器BeginStoryboardName屬性指定這個名稱,連接到相同的故事板,然后進行控制。
12、故事板事件。
故事板事件 | |
Completed | 動畫已經到達終點 |
CurrentGlobalSpeedInvalidated | 速度發生了變化,或者動畫被暫停、重新開始、停止或移到某個新的位置。 |
CurrentStateInvalidated | 動畫已經開始或結束。 |
CurrentTimeInvalidated | 動畫時鍾已經向前移動了一個步長,正在更改動畫。當動畫開始、停止或結束時也會引發該事件。 |
RemoveRequested | 動畫正在被移除。 |
監視動畫進度:
如果要監視動畫,要用到Storyboard的一些事件。在這里使用的是CurrentTimeInvalidated事件,每次向前移動動畫時鍾都會引發該事件。當引發CurrentTimeInvalidated事件時,發送者是Clock對象(Color類位於System.Windows.Media.Animation名稱空間中),可通過Clock對象檢索當前時間。當前時間使用TimeSpan對象表示,並且可檢索當前進度,當前進度使用0~1之間的數值表示。
后台代碼:
就是在上面的例子中為故事板加一個CurrentTimeInvalidated事件,然后再界面中放一個label控件(用於顯示時間)和ProgressBar(用於顯示進度,最大值為1,最小值為0)控件。
private void Storyboard_CurrentTimeInvalidated(object sender, EventArgs e) { Clock storyboardClock = (Clock)sender; if (storyboardClock.CurrentProgress == null) { lblTime.Content = ""; progressBar1.Value = 0; } else { lblTime.Content = storyboardClock.CurrentTime.ToString(); progressBar1.Value = (double)storyboardClock.CurrentProgress; } }
效果圖:
13、動畫緩動。
線性動畫有一個缺點,通常讓人覺得機械和不夠自然。改進動畫並創建更趨自然的動畫的秘訣是改變變化速率。不是創建以固定不變的速率改變屬性的動畫,而是需要設計根據某種方式加速或減速的動畫,實現更趨自然的動畫的最簡單方法是使用預置的緩動函數(EasingFunction)。EasyingFunction屬性只能接受單個緩動函數對象,所以不能為同一個動畫結合不同的緩動函數。
xaml代碼:
<Window.Resources>
<Style TargetType="Button">
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="Width">
<DoubleAnimation To="300" Duration="0:0:5">
<!--使用緩動函數-->
<DoubleAnimation.EasingFunction>
<!--設置緩動模式和振盪次數-->
<ElasticEase EasingMode="EaseOut" Oscillations="5"></ElasticEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Button Width="150" Height="50" Content="緩動動畫" FontSize="20"></Button>
</Grid>
效果圖:
14、緩動函數類。
在繼續分析不同的緩動類之前,理解緩動函數的應用時機是很重要的。所有的緩動函數類都繼承自EasingFunctionBase類,並且繼承了EasingMode屬性,EasingMode有三種值,分別是:EasyIn(在動畫開始時應用緩動效果)、EasyOut(動畫結束時應用緩動效果)和EasyInOut(在開始和結束時應用緩動動畫)。當應用緩動函數時不會改變動畫的持續時間。
緩動函數常用類 | ||
名稱 | 說明 | 屬性 |
BackEase | 當使用EaseIn模式應用該緩動函數時,在動畫開始之前拉回動畫,當使用EaseOut模式應用該緩動函數時,允許動畫稍微超越,然后拉回。 |
Amplitude屬性決定了拉回和超越的量。默認值是1,可減小該屬性值(大於0的任何值)以縮減效果,或增加該屬性值放大效果。 |
ElasticEase | 當使用EaseOut模式應用該緩動函數時,使動畫超越其最大值並前后擺動,逐漸減慢。當時用EaseIn模式應用該緩動函數時,動畫在其開始值周圍前后擺動,逐漸增加。 | Oscillations屬性控制動畫前后擺動的次數。 |
BounceEase | 執行與Elastic緩東函數類似的效果,只是彈跳永遠不會超越初始值或最終值。 | Bounce屬性控制動畫回調的次數(默認是2) |
CircleEase | 使用圓函數加速(使用EaseIn模式),或減速(使用EaseOut模式) | 無 |
CublicEase | 使用基於時間立方的函數加速,其效果與Circle類似,但是加速效果更緩和。 | 無 |
QuadraticEase | 使用基於時間平方的函數加速,效果與CublicEase類似,但加速過程更明顯。 | 無 |
QuarticEase | 無 | |
QuinticEase | 無 | |
SinEase | 無 | |
PowerEase | Power | |
ExponentialEase | Exponent |
15、自定義緩動函數。
創建自定義緩動函數一般需要以下幾個步驟:
a)、新建一個類,讓其繼承自EasingFunctionBase類。
b)、重寫EaseInCore()方法和CreateInstanceCore()方法。
c)、定義依賴屬性。
d)、引用。
后台代碼(自定義類):
public class RandomJitterEase : EasingFunctionBase { //聲明一個Random類,用於聲明隨機數。
Random rand = new Random(); /// <summary>
/// 重寫EaseCore方法。 /// </summary>
/// <param name="normalizedTime"></param>
/// <returns></returns>
protected override double EaseInCore(double normalizedTime) { //幾乎所有邏輯代碼都在EaseInCore方法中運行。該方法接受一個規范化的時間值,本質上是表示動畫進度從 //0到1之間的值,當動畫開始時,規范化的時間值是0,它從該點開始增加,直到在動畫結束點達到1. //在動畫運行期間,每次更新動畫的值時,WPF都會調用EaseInCore方法,確切的調用頻率取決於動畫的幀率。
if (normalizedTime == 1) { return 1; } else { return Math.Abs(normalizedTime - (double)rand.Next(0, 10) / (2010 - Jitter)); } } protected override System.Windows.Freezable CreateInstanceCore() { return new RandomJitterEase(); } //定義一個依賴屬性。
public static readonly DependencyProperty JitterProperty; //在靜態方法中注冊依賴屬性。
static RandomJitterEase() { JitterProperty = DependencyProperty.Register("Jitter", typeof(int), typeof(RandomJitterEase), new UIPropertyMetadata(1000), new ValidateValueCallback(ValidateJitter)); } public int Jitter { get { return (int)GetValue(JitterProperty); } set { SetValue(JitterProperty, value); } } //此方法用於判斷值。
private static bool ValidateJitter(object value) { int jitterValue = (int)value; if (jitterValue <= 2000 && jitterValue >= 0) { return true; } else { return false; } } }
xaml代碼:
<Window x:Class="自定義緩動函數.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:自定義緩動函數" Title="MainWindow" Height="350" Width="525">
<Window.Triggers>
<!--事件觸發器,窗體加載的Loaded事件。-->
<EventTrigger RoutedEvent="Window.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Canvas.Left)" From="0" To="480" Duration="0:0:5"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="ellipse2" Storyboard.TargetProperty="(Canvas.Left)" From="0" To="480" Duration="0:0:5">
<DoubleAnimation.EasingFunction>
<!--調用自定義緩動函數類-->
<local:RandomJitterEase EasingMode="EaseIn" Jitter="1500"></local:RandomJitterEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<Canvas ClipToBounds="True">
<Ellipse Name="ellipse1" Width="25" Height="25" Fill="Red"></Ellipse>
<Ellipse Margin="0,70,0,0" Name="ellipse2" Width="25" Height="25" Fill="Green"></Ellipse>
</Canvas>
</Window>
效果圖:
16、WPF動畫性能和幀率。
通常,為用戶界面應用動畫,只不過是創建並配置正確的動畫和故事版對象。但在其他情況下,特別是同時發生多個動畫時,可能更加需要關注性能。WPF試圖保持以60幀/秒的速度進行動畫,可以確保從開始到結束得到平滑流暢的動畫。幀速率越低,會發生抖動現象。幀速率越高,占用的CPU也就越高。通過TimeLine.DesiredFrameRate屬性進行調整。
xaml代碼:
<Window x:Class="動畫性能之幀率.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:動畫性能之幀率" Title="MainWindow" Height="500" Width="525">
<Window.Triggers>
<!--定義一個事件觸發器,通過SourceName屬性關聯button-->
<EventTrigger RoutedEvent="Button.Click" SourceName="btn_start">
<EventTrigger.Actions>
<BeginStoryboard>
<!--通過Timeline.DesiredFrameRate屬性設置幀速率-->
<Storyboard Storyboard.TargetName="ellipse" Timeline.DesiredFrameRate="{Binding ElementName=txtBox1, Path=Text}">
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" From="0" To="300" Duration="0:0:10"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" From="0" To="250" Duration="0:0:10"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<Grid ShowGridLines="False">
<Grid.RowDefinitions>
<RowDefinition Height="5*"></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions >
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Canvas ClipToBounds="True" Grid.Row="0" Grid.ColumnSpan="2" Height="320" Background="Beige">
<Ellipse Name="ellipse" Fill="Red" Width="10" Height="10"></Ellipse>
</Canvas>
<Label Grid.Row="1" Content="幀速率:" FontSize="20" HorizontalAlignment="Right" VerticalAlignment="Center"></Label>
<TextBox Name="txtBox1" Text="1" Width="60" Height="30" FontSize="20" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center"></TextBox>
<Button Name="btn_start" Grid.Row="2" Grid.ColumnSpan="2" Width="200" Height="60" Content="點擊動畫" FontSize="20"></Button>
</Grid>
</Window>
效果圖: