在Android系統中,有插值動畫,數值動畫,屬性動畫,幀動畫。
幀動畫,在SOUI里可以通過AnimateImg這個控件來實現,其它幾種動畫3.0之前不支持,需要類似動畫效果,只能自己通過定時器去實現,實現成本比較高。
SOUI3.0增加了插值動畫和數值動畫支持,屬性動畫可以通過數值動畫來實現,因此沒有專門移植。
這一講我先講插值動畫。
有Android開發經驗的朋友,應該知道Android的插值動畫有AlphaAnimation, TranslationAnimation, ScaleAnimation, RotateAnimation, AnimationSet這5個類,它們都有共同的基類Animation。
3.0把這些Animation都移植到了SOUI。
在SOUI使用插值動畫和Android中類似,先通過XML定義好一個動畫,然后加載動畫,再交給SWindow去播放動畫。
下面以AnimationSet為例來說明如何使用。
1、定義動畫XML:
<?xml version="1.0" encoding="utf-8"?> <set repeatCount="-1"> <alpha duration="500" fromAlpha="1.0" toAlpha="0.5" repeatCount="1" repeatMode="reverse"/> <rotate duration="500" startOffset="1000" fromDegrees="0" toDegrees="360" pivotX="50%" pivotY="50%" repeatMode="restart" repeatCount="0" interpolator="linear"/> <set startOffset="1500"> <scale duration="500" fromXScale="1.0f" toXScale="0.5" fromYScale="1.0" toYScale="0.5" repeatCount="1" repeatMode="reverse"/> </set> </set>
上面代碼來自demo\uires\Anim\rotate.xml
這個XML描述的是一個AnimationSet動畫,里面包含了一個AlphaAnimation,一個RotateAnimation及另一個包含ScaleAnimation的AnimationSet。
首先可以看到最外層的set有一個repeatCount屬性,值為-1,代表無限重復。
然后我們注意到這里第一個alpha動畫,duration=500代表這個動畫執行一次需要500ms, 再注意它有一個repeatCount=1,代表這個動畫執行2次,repeatMode=reverse,代表這個動畫第一次alpha從1.0到0.5, 第二次重復的時候變成從0.5到1.0。
然后我們注意一下第二個rotate動畫,它多了一個startOffset=1000,這個1000正好是上一個動畫的總執行時間,也就是說這個rotate動畫是在alpha動畫完成之后再執行。fromDegree, toDegree, pivotX, pivotY是rotate動畫的專有屬性,含義見代碼。這里注意一下interpolator屬性,interpolator代碼插值器類型,如果不指定這個屬性,系統默認使用AccelerateDecelerate插值器,這個插值器是先加速再減速。上面例子則調整為線性插值器。
最后再看它的第3個子動畫,它也是一個set動畫。它從1500MS開始,正好是上一個rotate動畫結束。這個set里只有一個scale動畫,它先縮小到50%,后放大100%。
整個動畫過程分成了3段,它們在時間是連續的,總共執行2500MS。
當然這些子動畫完全可以同步進行,也可以不連續。
2、加載動畫:
和所有SOUI其它資源一樣,首先這個XML應該放到uires目錄下,並且在uires.idx文件能夠正確引用到這個文件。
<anim> <file name="love" path="anim\love.xml"/> <file name="slide_show" path="anim\slide_show.xml"/> <file name="slide_hide" path="anim\slide_hide.xml"/> <file name="rotate" path="anim\rotate.xml"/> </anim>
最后一個name=rotate就是這個動畫資源。
配置好資源,就可以在代碼中引用這個動畫了:
void CMainDlg::InitSoui3Animation() { SWindow *pWnd = FindChildByName(L"img_soui"); if (pWnd) { IAnimation *pAni = SApplication::getSingletonPtr()->LoadAnimation(L"anim:rotate"); if(pAni) { pWnd->SetAnimation(pAni); pAni->Release(); } } }
通過SAppliation::LoadAnimation來加載這個動畫。
3、將這個動畫交給SWindow來播放。注意上面代碼中的pWnd->SetAnimation,這樣這個動畫就會立即播放。SetAnimation會在SWindow內部持有這個IAnimation,因此這里還需要調用pAni->Release(),以保證動畫資源不使用后能釋放內存。如果希望動畫延時播放,可以調用pAni->SetStartOffset()來配置。
下圖是這個動畫在demo中的執行效果:

截圖時間軸不太准確,具體見demo。
注意:SOUI的AnimationSet和Android的AnimationSet有兩個區別:
1、SOUI的AnimationSet支持repeatCount屬性,但不支持repeatMode屬性。
2、和SOUI相反,Android的AnimationSet支持repeatMode屬性,但不支持repeatCount屬性。
實際上Android的repeatMode屬性意義不大,它不過是把這個屬性直接傳遞給它的子動畫對象,並不是作用於AnimationSet本身。考慮到如果和Android一樣支持repeatMode傳遞給子對象可能會產生誤解,SOUI中干脆就不支持這個屬性了。需要的話,直接在子對象上設置這個屬性就好了。
啟程軟件 2019年8月4日
