Windows Phone的動畫實作方式有線性插值動畫(3種類型)、關鍵祯動畫(4種類型)和基于幀動畫,甚至還有定時器動畫,然後動畫所改變的UI元素屬性可以是普通的UI元素屬性,變換特效屬性和三維特效屬性,面對着這麼多的選擇,我們要實作一個動畫效果該怎麼去思考動畫實作的思路以及怎麼選擇實作的技術呢?那麼我們這小節會先講解與動畫性能相關的知識,然後再講解怎麼去選擇動畫的實作方案。
幀速率是用于測量顯示幀數的量度,測量機關為“每秒顯示幀數”(Frame per Second,FPS,幀率)或“赫茲”,是指每秒鐘重新整理的畫面的幀數,也可以了解為圖形處理器每秒鐘能夠重新整理幾次。由于人類眼睛的特殊生理結構,如果所看畫面之幀率高于每秒約10-12幀的時候,就會認為是連貫的。對于動畫而言,幀速率常用于衡量動畫的流暢度,幀速率的數字越大表示動畫的流暢度越高。在實作Windows Phone動畫的時候,我們是不能夠直接指定動畫的幀速率的,動畫的幀速率是由系統自動配置設定的,當手機的性能越好,程式的性能越好,那麼動畫的幀速率就越大,反之就越小。是以要判斷一個動畫是否能夠流暢地運作,我們需要關注動畫的幀速率名額是否足夠高。
在Windows Phone裡面雖然不能夠直接設定動畫的幀速率,但是可以測量出來。當在Windows Phone模拟器中運作應用時,可以使用幀速率計數器來監控應用的性能和動畫的效率,模拟器的效果圖如圖8.1所示,每一個幀速率計數器的作用如表8.1所示。當然幀速率計數器也一樣可以在手機上進行顯示,在真實的 Windows Phone 手機上測試這些計數器非常重要,因為模拟器的性能和在真實的手機上是有很大差別的。對于每個計數器的值都有建議門檻值和上限門檻值,如表8.2所示,當計數器在紅色值門檻值區間表明存在潛在性能問題,這就需要引起重視,你的動畫的實作方案可能有較大的問題,需要進行優化。
那麼幀速率計數器是可以在代碼中啟用或禁用的,當你在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)

WP8.1技術交流群:372552293
本文轉自linzheng 51CTO部落格,原文連結:http://blog.51cto.com/linzheng/1559357