Windows Phone的動畫實現方式有線性插值動畫(3種類型)、關鍵禎動畫(4種類型)和基於幀動畫,甚至還有定時器動畫,而後動畫所改變的UI元素屬性能夠是普通的UI元素屬性,變換特效屬性和三維特效屬性,面對着這麼多的選擇,咱們要實現一個動畫效果該怎麼去思考動畫實現的思路以及怎麼選擇實現的技術呢?那麼咱們這小節會先講解與動畫性能相關的知識,而後再講解怎麼去選擇動畫的實現方案。html
幀速率是用於測量顯示幀數的量度,測量單位爲「每秒顯示幀數」(Frame per Second,FPS,幀率)或「赫茲」,是指每秒鐘刷新的畫面的幀數,也能夠理解爲圖形處理器每秒鐘可以刷新幾回。因爲人類眼睛的特殊生理結構,若是所看畫面之幀率高於每秒約10-12幀的時候,就會認爲是連貫的。對於動畫而言,幀速率經常使用於衡量動畫的流暢度,幀速率的數字越大表示動畫的流暢度越高。在實現Windows Phone動畫的時候,咱們是不可以直接指定動畫的幀速率的,動畫的幀速率是由系統自動分配的,當手機的性能越好,程序的性能越好,那麼動畫的幀速率就越大,反之就越小。因此要判斷一個動畫是否可以流暢地運行,咱們須要關注動畫的幀速率指標是否足夠高。編程
在Windows Phone裏面雖然不可以直接設置動畫的幀速率,可是能夠測量出來。當在Windows Phone模擬器中運行應用時,可使用幀速率計數器來監控應用的性能和動畫的效率,模擬器的效果圖如圖8.1所示,每個幀速率計數器的做用如表8.1所示。固然幀速率計數器也同樣能夠在手機上進行顯示,在真實的 Windows Phone 手機上測試這些計數器很是重要,由於模擬器的性能和在真實的手機上是有很大區別的。對於每一個計數器的值都有建議閾值和上限閾值,如表8.2所示,當計數器在紅色值閾值區間代表存在潛在性能問題,這就須要引發重視,你的動畫的實現方案可能有較大的問題,須要進行優化。緩存
表8.2 建議的幀和填充速率佈局
計數器性能 |
紅色閾值*測試 |
建議值優化 |
上限閾值動畫 |
構圖線程幀速率this |
30 幀/秒spa |
45 幀/秒 |
60 幀/秒 |
UI 線程幀速率 |
15 幀/秒 |
30 幀/秒 |
60 幀/秒 |
屏幕填充速率 |
>3 |
<= 2.5 |
3.0 |
那麼幀速率計數器是能夠在代碼中啓用或禁用的,當你在Visual Studio中建立 Windows Phone應用項目時,默認狀況下會在文件 App.xaml.cs 中添加啓用幀速率計數器的代碼。代碼以下所示:
if (System.Diagnostics.Debugger.IsAttached)
{
this.DebugSettings.EnableFrameRateCounter = true;
}
上面的代碼表示當啓動Debug狀態調試應用程序的時候將會啓用幀速率計數器。其中Application.Current.Host.Settings.EnableFrameRateCounter = true表示啓用幀速率計數器,設置爲false則禁用幀速率計數器。
Windows Phone的圖形線程結構針對手機進行了優化,除了UI線程以外,Windows Phone 還支持構圖線程。若要掌握怎麼去選擇最優的動畫實現方案,那麼須要理解Windows Phone 中UI線程和構圖線程,這對作動畫的優化是很是重要的。
(1)UI 線程
UI 線程是Windows Phone中的主線程,UI線程的主要任務是從 XAML 中分析並建立對象、在第一次繪製視覺效果時,將繪製全部視覺效果以及處理每幀回調並執行其餘用戶代碼。在應用程序裏面維護輕量級的UI線程是保障應用程序流暢運行的前提,同時這對於動畫的實現也是同樣的道理,儘可能避免佔用UI線程。
(2)構圖線程
構圖線程能夠處理某些在UI上的工做,從而分擔了UI線程的部分工做,提升Windows Phone應用的性能。在Windows Phone上,構圖線程的工做是,它合併圖形紋理並將其傳遞到 GPU 以供繪製,手機上的 GPU 將在稱爲自動緩存的進程中,自動緩存並處理運行在構圖線程上的動畫。構圖線程處理與變換特效(RenderTransform)和三維特效(Projection)屬性關聯的動畫,如針對於ScaleTransform、TranslateTransform、RotateTransform和PlaneProjection的屬性改變的Storyboard動畫都是徹底運行在構圖線程上的。另外,Opacity 和 Clip 屬性設置也由構圖線程處理。可是,若是使用 OpacityMask或非矩形剪輯,則這些操做將被傳遞到 UI 線程。
(3)動畫和線程
從構圖線程的做用能夠知道StoryBoard動畫由構圖線程進行處理,那麼這種動畫的處理方式最爲理想,由於構圖線程會將這些動畫傳遞到GPU進行處理。若是須要在動畫中使用到UI線程,如改變UI元素的With屬性等,那麼就須要給動畫相應的Animation對象的EnableDependentAnimation屬性設置爲True,它表示動畫是否須要依賴UI線程來運行。此外,若是 CPU 超負荷,則構圖線程可能比UI線程運行的更頻繁。可是,有時Storyboard動畫沒法實現你的動畫效果的時候,你能夠選擇在代碼中驅動動畫,如採用基於幀動畫。這些動畫按幀進行處理,每幀回調都在UI線程上進行處理,動畫的更新速度與UI線程處理動畫的速度至關,而且根據應用中發生的其餘操做,動畫顯示的流暢性可能低於在構圖線程上運行的動畫。另外,當使用基於幀動畫在代碼中更新動畫時,UI元素不會像在Storyboard動畫中更新同樣,自動進行緩存,這又加劇了UI線程的負擔。
上一章咱們講解了不少的動畫的變成知識,這些都是Windows Phone動畫編程的根基,正所謂萬變不離其宗,不管你要實現的動畫懂麼複雜,都離不開這些基礎知識。當咱們要去實現一個動畫效果的時候,首先須要去思考動畫中的每一個組成元素,思考它們的變化狀況,想一下要改變UI元素的什麼屬性來實現動畫的效果,想一下用什麼動畫類型來實現。當你已經想到了有多種方案能夠實現這個動畫效果的時候,你能夠從兩個方面去衡量你的實現方案,一方面是從性能效率方面,這就涉及到前面所講的動畫的幀速率,UI線程和構圖線程相關的知識;另外一方面是從動畫實現的複雜度方面,好比要實現一個很複雜圖形的形狀變化的動畫,你能夠直接用Path圖形來繪製出這個圖形,而後設計Path圖形的點運動的動畫,也能夠用多張相似的圖片作圖片切換的動畫,若是圖片切換的動畫效果能達到你所想要的效果,那麼就建議使用圖片切換這種簡單的方式來實現。
在Windows Phone中有多種實現動畫的方案,關於這些方案的選擇有下面的一些建議。
(1)能夠用變換特效屬性或者三維特效屬性實現的動畫,應該儘可能採用變換特效屬性或者三維特效屬性做爲動畫改變的屬性去實現動畫。由於變換特效屬性或者三維特效屬性是經過構圖線程對UI元素產生做用的,不會阻塞UI線程也不會從新調用UI的佈局系統。
(2)可使用線性插值動畫/關鍵幀動畫來實現的動畫就採用線性插值動畫/關鍵幀動畫去實現,由於線性插值動畫/關鍵幀動畫是最優的動畫實現方式,它們自己也是在構圖線程上運行的。
(3)當使用線性插值動畫/關鍵幀動畫沒法實現的動畫效果的時候應該採用基於幀動畫來實現,而不是自定義定時器來實現動畫,基於幀動畫比定時器動畫更勝一籌,它能夠根據設備和應用程序的狀況動態地跳幀調用的頻率。
下面咱們經過一個例子來演示用兩種不一樣的方法來實現一個相同的動畫效果,所實現的動畫效果是讓矩形的高度慢慢地變成原來的兩倍,第一種方式是用線性插值動畫對矩形的Height屬性進行動畫處理,第二種方式也是用線性插值動畫,可是針對的動畫目標屬性是ScaleTransform的ScaleY屬性,而後咱們用一個按鈕點擊事件阻塞UI線程2秒鐘,能夠看到針對Height屬性的動畫會暫停2秒鐘再繼續運行,而針對ScaleTransform的ScaleY屬性不會受UI線程阻塞的影響。示例代碼以下所示:
代碼清單8-1:兩種動畫的對UI線程的影響(源代碼:第8章\Examples_8_1)
MainPage.xaml文件主要代碼 ------------------------------------------------------------------------------------------------------------------ < Page.Resources> <Storyboard x:Name="heightStoryboard"> <!--針對Height屬性的動畫--> <DoubleAnimation Storyboard.TargetName="rectangle1" Storyboard.TargetProperty="Height" RepeatBehavior="Forever" EnableDependentAnimation="True" From="100" To="200" Duration="0:0:2"> </DoubleAnimation> </Storyboard> <Storyboard x:Name="scaleTransformStoryboard"> <!--針對ScaleTransform的ScaleY屬性的動畫--> <DoubleAnimation Storyboard.TargetName="scaleTransform1" Storyboard.TargetProperty="ScaleY" RepeatBehavior="Forever" From="1" To="2" Duration="0:0:2"> </DoubleAnimation> </Storyboard> </ Page.Resources> <StackPanel> <Button Content="阻塞UI線程" Click="Button_Click_1"></Button> <Button x:Name="heightAnimationButton" Content="Height屬性動畫" Click="heightAnimationButton_Click_1"></Button> <Button x:Name="scaleTransformAnimationButton" Content="ScaleTransform屬性動畫" Click="scaleTransformAnimationButton_Click_1"></Button> <Rectangle Height="100" Fill="Blue" x:Name="rectangle1"> <Rectangle.RenderTransform> <ScaleTransform x:Name="scaleTransform1" ></ScaleTransform> </Rectangle.RenderTransform> </Rectangle> </StackPanel>
MainPage.xaml.cs文件主要代碼 ------------------------------------------------------------------------------------------------------------------ private void Button_Click_1(object sender, RoutedEventArgs e) { // 阻塞UI線程2秒鐘 Task.Delay(2000).Wait(); } private void heightAnimationButton_Click_1(object sender, RoutedEventArgs e) { // 播放改變高度屬性的動畫,高度有100變成200 scaleTransformStoryboard.Stop(); heightStoryboard.Begin(); } private void scaleTransformAnimationButton_Click_1(object sender, RoutedEventArgs e) { // 播放改變變換屬性的動畫,舉行沿着X軸放大2倍 heightStoryboard.Stop(); scaleTransformStoryboard.Begin(); }
本文來源於《深刻理解Windows Phone 8.1 UI控件編程》
源代碼下載:http://vdisk.weibo.com/s/zt_pyrfNHoezI
歡迎關注個人微博@WP林政
WP8.1技術交流羣:372552293