在API Demo的View->Animation下可以找到四個Animation的Demo,第一個3D Translate比較複雜,最後再講,先講第2個Interpolator。該Activity對應的是view包內的Animation3.java,和layout的animation_3.xml。
介面的布局不加解釋了,就一個Spinner和一個TextView。不是本文內容。
主要解釋下幾個重點語句。
初始化Animation,從類的名字可以看出是一個變換View的位置的動畫,參數起點橫座標,終點橫座標,起點縱座標,終點縱座標。
Animation a = new TranslateAnimation(0.0f, targetParent.getWidth() - target.getWidth() - targetParent.getPaddingLeft() - targetParent.getPaddingRight(), 0.0f, 0.0f);
下面是動畫的參數設定,我加上了注釋
a.setDuration(1000);//設定動畫所用的時間 a.setStartOffset(300);//設定動畫啟動的延時 //設定重複模式,RESTART為結束後重新開始,REVERSE為按原來的軌跡逆向返回 a.setRepeatMode(Animation.RESTART); //設定重複次數,INFINITE為無限 a.setRepeatCount(Animation.INFINITE); //根據使用者在Spinner的選擇設定target的進入的方式 switch (position) { case 0: //加速進入 a.setInterpolator(AnimationUtils.loadInterpolator(this.R.anim.accelerate_interpolator)); break; case 1: //減速進入 a.setInterpolator(AnimationUtils.loadInterpolator(this, android.R.anim.decelerate_interpolator)); break; case 2: //加速進入.與第一個的區別為當repeatMode為reverse時,仍為加速返回原點 a.setInterpolator(AnimationUtils.loadInterpolator(this, android.R.anim.accelerate_decelerate_interpolator)); break; case 3: //先往後退一點再加速前進 a.setInterpolator(AnimationUtils.loadInterpolator(this, android.R.anim.anticipate_interpolator)); break; case 4: //減速前進,衝過終點前再後退 a.setInterpolator(AnimationUtils.loadInterpolator(this, android.R.anim.overshoot_interpolator)); break; case 5: //case 3,4的結合體 a.setInterpolator(AnimationUtils.loadInterpolator(this, android.R.anim.anticipate_overshoot_interpolator)); break; case 6: //停止前來回振幾下 a.setInterpolator(AnimationUtils.loadInterpolator(this, android.R.anim.bounce_interpolator)); break; } //讓target開始執行這個動畫 target.startAnimation(a); }
這裡使用的是Android已預設的一些動作,我們也可以自訂XML來實現更好看的動畫效果的,這個下一篇再講。
除了TranslationAnimation,還有AlphaAnimation、RotateAnimation、ScaleAnimation,使用這幾個基體動作的組合,可以形成一系列複雜的動畫效果。具體用法請查看SDK。
整個都比較簡單,就一個函數的調用,還不懂的看一下API的注釋和SDK文檔,沒什麼難理解的。
現在開始看第三個Push,從View->animation->Push可以啟動這個Activity
Push這個Demo主要是展示了View之間的轉場效果。
Push對應的Java檔案為view包內的Animation2.java,對應的XML布局檔案為layout/animation_2.xml。
先看布局檔案,這個頁面內最主要用到的是一個ViewFlipper。使用ViewFlipper可以實現多個View之間的動態切換,並且可以自訂切換開關動畫,本例中所展示的就是如何定義切換動畫。
下面只挑重點語句來講了。
讓ViewFlipper開始自動切換。
mFlipper.startFlipping();
當點擊時Spinner內的選項時,更改進入和退出的動畫效果。
public void onItemSelected(AdapterView parent, View v, int position, long id) { switch (position) { case 0: mFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_up_in)); mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_up_out)); break; case 1: mFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_in)); mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_out)); break; case 2: mFlipper.setInAnimation(AnimationUtils.loadAnimation(this.R.anim.fade_in)); mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out)); break; default: mFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.hyperspace_in)); mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.hyperspace_out)); break; } }
這裡的Animation都是自訂的動畫效果,可以在res/anim內找到對應的XML檔案,下面用push_up_in.xml來說明定義的大概用法。
因為這個動畫是由幾個動畫複合組成的,所以外圍就用一個set標籤括起來,組成一個AnimationSet。
translate標籤內主要定義位置的變化情況,fromYDelta="100%p",是指從ViewFlipper的正下方剛好一個View的高度的距離的地方開始出現,100%p是一個相對值,大於0為下方,小於0為上方。toYDelta="0",是指剛好達到布局檔案的原始位置停止。android:duration="300",是指整個動作的時間用時為300毫秒,系統會根據這個時間自動調整速度。
alpha標籤內定義的是透明度,0為全透明,1.0為不透明,過程為300毫秒,讓View為逐漸出現的過程
<set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromYDelta="100%p" android:toYDelta="0" android:duration="300"/> <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" /> </set>
push_up_out.xml,和push_left的兩個標籤都幾乎一樣的,應該很好理解。
hyperspace_in.xml更簡單,只有一個alpha,所以外層沒有set標籤。startOffset是設定延遲。
hyperspace_out.xml相對複雜一點,set裡面還包括有set,但仍然是由幾個小動作一起組成的,可以一點點拆成來理解。
最外層是一個set,裡面嵌套一個scale和一個set。
第一個scale標籤可以理解為,以當前View的正中間位置為軸點,在700毫秒時間內,以加速放大的方式,將View的橫長變為1.4倍,高度變為0.6倍。至於fillAfter這個標籤我一直搞不懂這個功能,照SDK裡的解釋,是在連續動畫中讓View保持在動畫的最後一幀,但照我的實驗似乎沒有什麼效果,這個求高手指教。(查網上一些資料是說必須在代碼裡設定,這個是不是屬於Android的Bug?)一個animationSet可以做為另一個animationSet的子集,這個很容易理解。rotate標籤內的照字面意思應該很容易理解了,不再贅述了。
<set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false"> <scale android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:fromXScale="1.0" android:toXScale="1.4" android:fromYScale="1.0" android:toYScale="0.6" android:pivotX="50%" android:pivotY="50%" android:fillAfter="false" android:duration="700" /> <set android:interpolator="@android:anim/accelerate_interpolator" android:startOffset="700"> <scale android:fromXScale="1.4" android:toXScale="0.0" android:fromYScale="0.6" android:toYScale="0.0" android:pivotX="50%" android:pivotY="50%" android:duration="400" /> <rotate android:fromDegrees="0" android:toDegrees="-45" android:toYScale="0.0" android:pivotX="50%" android:pivotY="50%" android:duration="400" /> </set> </set>
很多動畫其實都是通過alpha, scale, rotate, translate這幾個基本動作組成的。這些都屬於Tween Animation。另外還有一種Frame Animation,類似放電影的效果,一幀幀播放動畫,以後再說。
所有在XML內的設定的屬性都可以在JAVA裡找到對應的API函數,在Android SDK文檔裡可以查得到。
其實我覺得我這樣寫得都有點囉嗦了,Android的API的名字定義都很規範,從名字都已經可以判斷出這個函數的功能了。
3D Transition的主要定義在animation包內,裡面只有兩個Java檔案。
3D翻轉其實並不是很複雜,最主要的是一個函數rotation.setAnimationListener(new DisplayNextView(position));在Transition3d的第99行。這個函數的主要作用是通過一個Listener,設定動畫開始前、結束後,和重複動作時要觸發的事件。
3D翻轉效果主要由兩個rotato動作構成,第二個動作在第一個動作完成後,由Listener來啟動。這兩個Animation連起來,看的時候就像3D旋轉的效果了。
同時,在Rotate3dAnimation.java中,重新定義了一個Animation,覆寫了initialize和applyTransformation方法。initialize是初始化動作,applyTransformation就定義動畫效果的,這個是最主要的部分,傳進來的是目前時間為總時間的百分比和動作,這裡利用了轉換矩陣。發現我的線性代數都忘了T_T,以後要重新看一遍。主要這個Camara不太理解,注釋裡也沒寫有這個類有什麼用,從代碼裡猜測這個是儲存當前的介面。
這樣說來是簡單,但做起來難啊。。