Android動畫淺析,android淺析
前言
在應用的開發中,動畫是必不可少的一部分,否則很多視覺效果會顯得特別突兀。今天我們就來瞭解一下Android中的動畫庫。
View中實現動畫的過程
View的alpha動畫直接通過setAlpha(float al)函數來修改透明度實現,縮放、平移、旋轉等都是通過圖形矩陣變換來實現。圖形變換是圖形學中基本知識,簡單來說就是,每種變換都是一次矩陣運算。在Android中,Canvas類包含當前矩陣,當前調用Canvas.drawBitmap(bm,x,y,Paint)繪製時,android會先把bmp做一次矩陣運算,然後將運算結果顯示在Canvas上。這樣編程人員只需不斷修改Canvas的矩陣並重新整理螢幕,View裡對象就會不停的做圖形變換,動畫就形成了。
View設定動畫,設定動畫屬性,在動畫啟動時,會調用invalidate方法重繪View。從而觸發onDraw函數;在onDraw函數中,調用動畫的getTransformation方法,得到目前時間點的矩陣,getTransformation函數又會調用動畫的applyTransformation函數,applyTransformation函數通過一個計算因子 (由插值器通過動畫執行的百分比計算出來的因子)來計算當前時刻View屬性的值,修改View的屬性達到圖形變換。View會判斷getTransformation的傳回值,若為真,說明動畫未完成,調用invalidate方法重新整理螢幕,重繪View,從而進入下一幀動畫,再次執行上述過程;若為假,說明動畫完成。
動畫的分類Android平台為我們提供了兩類動畫,Tween(補間動畫)動畫和Frame(幀)動畫。Tween動畫是通過對情境中的對象不斷進行映像變換(平移、縮放、旋轉等)來產生動畫效果的;Frame動畫則是順序播放事先做好的每幀映像,類似於快速的投影片一樣。補間動畫Tween動畫是通過預先定義一個動畫,這個動畫指定了圖形變換的類型(旋轉、平移、縮放等)、啟動時間、期間、起始值,在View繪製時就會沿著時間軸修改這些屬性值,從而達到動畫效果。動畫可以通過代碼定義,也可以通過xml來定義。如果動畫是在xml中定義的,那麼使用AnimationUtils.loadAnimation(context, R.anim.your_anim);來載入即可。 Alpha:透明度動畫該動畫是在指定的時間段內修改View的透明度,從0.3到1.0f的透明度動畫樣本如下 : 代碼定義動畫 :
AlphaAnimation alphaAnimation = new AlphaAnimation(0.3f, 1.0f) ; alphaAnimation.setDuration(1000);
xml 定義動畫:
<?xml version="1.0" encoding="utf-8"?> <!-- 透明度 --> <alpha xmlns:android="http://schemas.android.com/apk/res/android" android:fromAlpha="1" android:toAlpha="0" android:duration="1000" />
然後執行通過view的setAnimation或者startAnimation設定動畫即可。
Scale:縮放動畫對view的縮放動畫,需要指定x, y軸上各自的縮放值。樣本為在一秒中之內把View縮放為原來的一半大小,縮放的中心點為view的中心。代碼定義動畫:
ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 0.5f, 1.0f, 0.5f,0.5f, 0.5f); scaleAnimation.setDuration(1000);
xml 定義動畫:
<?xml version="1.0" encoding="utf-8"?> <!-- 縮放 --> <scale xmlns:android="http://schemas.android.com/apk/res/android" android:fromXScale="1" android:fromYScale="1" android:toXScale="0.5" android:toYScale="0.5" android:pivotX="0.5" android:pivotY="0.5" android:duration="3000" />
Translate:位移動畫位移動畫是將View從一個點移動到某一個點的動畫。例如將view在一秒鐘內從(0,0)位置移動到(100, 100)位置。代碼定義:
TranslateAnimation translateAnimation = new TranslateAnimation(0, 100, 0, 100) ; translateAnimation.setDuration(1000);
XML定義動畫 :
<?xml version="1.0" encoding="utf-8"?> <!-- 移動 --> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:fromXDelta="0" android:fromYDelta="0" android:toXDelta="100" android:toYDelta="100" android:duration="000" />
Rotate:旋轉動畫旋轉動畫負責對view的角度進行調整,例如將view從當前角度旋轉360度。代碼定義:
RotateAnimation rotateAnimation = new RotateAnimation(0, 360) ; rotateAnimation.setDuration(1000);
XML定義:
<?xml version="1.0" encoding="utf-8"?> <!-- 旋轉 --> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:fromDegrees="0" android:toDegrees="360" android:pivotX="50%" android:pivotY="50%" android:duration="1000" />
幀動畫
幀動畫可以想象為一部很短的電影,他由數量有限的主要畫面格組成,當這個幀動畫時這些主要畫面格快速的切換,從而達到動畫的效果。
<?xml version="1.0" encoding="utf-8"?><animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/p1" android:duration="200" /> <item android:drawable="@drawable/p2" android:duration="200" /> <item android:drawable="@drawable/p3" android:duration="200" /> <item android:drawable="@drawable/p4" android:duration="200" /> <item android:drawable="@drawable/p5" android:duration="200" /> <item android:drawable="@drawable/p6" android:duration="200" /> <item android:drawable="@drawable/p7" android:duration="800" /> <item android:drawable="@drawable/p8" android:duration="200" /> <item android:drawable="@drawable/p9" android:duration="200" /> <item android:drawable="@drawable/p10" android:duration="200" /> <item android:drawable="@drawable/p11" android:duration="200" /></animation-list>
使用幀動畫與補間動畫不太一樣,樣本如下 :
// 通過逐幀動畫的資源檔獲得AnimationDrawable樣本 AnimationDrawable frameAnim = (AnimationDrawable) getResources().getDrawable(R.drawable.my_frame_anim);// 把AnimationDrawable設定為myView的背景myView.setBackgroundDrawable(frameAnim);
動畫的插值器(Interpolator)
在補間動畫中,我們一般只定義首幀和尾幀,然後由系統自動產生中間幀,產生中間幀的這個過程可以成為“插值”。插值器的作用是告訴動畫某個屬性(比如顏色的漸層)如何隨時間變化 ,在duration周期內每個時刻對應的屬性值。下面是幾種常見的插值器:
android 系統預設支援AccelerateDecelerateInterpolator 、 AccelerateInterpolator 、 AnticipateInterpolator 、AnticipateOverShootInterpolator 、 BounceInterpolator 、 CycleInterpolator 、DecelerateInerpolator 、 LinearInterpolator 、 OverShootInterpolator 共 9 種插值器(若這些插值器不能滿足需求,則可以自訂插值器)。
例如,一個alpha動畫在一秒內從0.0f到1.0f變換,線性插值器的動畫為勻速執行的。但是加速插值器的動畫會隨著時間的增加而越來越快。
插值器通過getInterpolation方法獲得插值因子,插值因子的計算也在此函數中完成。例如線性插值器,它的動畫則是勻速運動的,因此在它的getInterpolation函數中插值因子只跟時間相關,與其他因素無關。getInterpolation(int inpput)函數中的參數即動畫執行的百分比,也可以認為是動畫已經執行時間和動畫周期的百分比。該值為0.0f 到 1.0f,即動畫的開始到結束。
/** * An interpolator where the rate of change is constant * */public class LinearInterpolator implements Interpolator { public LinearInterpolator() { } public LinearInterpolator(Context context, AttributeSet attrs) { } public float getInterpolation(float input) { return input; }}再看加速插值器,即動畫的速度會隨著時間的推移而越來越快。我們看看它的getInterpolation實現:
public float getInterpolation(float input) { if (mFactor == 1.0f) { return input * input; } else { return (float)Math.pow(input, mDoubleFactor); } }預設情況下mFactor會為1.0f, 隨著動畫的執行,input慢慢增大,getInterpolation函數返回的數值的大小變化範圍會越來越大,從而導致動畫變快。
使用矩陣Matrix自訂動畫
自訂動畫時,我們主要就是覆寫applyTransformation(float interpolatedTime, Transformation t) 方法,在方法是在動畫執行時就是調用該方法來實現動畫操作,我們在這裡需要實現修改alpha, 縮放,平移等動畫。interpolatedTime是由插值器計算出來的因子,由動畫的執行百分比與插值器的策略計算而來,值為0.0f 到 1.0f。參數t為矩陣變換的封裝類。在這裡我們只討論使用矩陣實現的自訂動畫。例如,我們需要定製一個動畫,是它能夠在低於API 11 版本的系統裡實現Y軸的旋轉動畫,android中的RorateAnimation動畫只支援在Z軸上的旋轉動畫,這是我們就可以通過矩陣來實現。關於矩陣的資料,請移步,Android中映像變換Matrix的原理、代碼驗證和應用(一),Android Matrix理論與應用詳解,Android--Matrix圖片變換處理。
/** * @author mrsimple */public class RotateYAnimation extends Animation { private int halfWidth; private int halfHeight; // 使用Camera實現3D旋轉 Camera mCamera = new Camera(); // protected float mRotateY = 0.0f; /** * width,height為執行該動畫的view的寬度、高度。後面兩個參數為執行該動畫的view的parent的寬度、高度 */ @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); setDuration(2000); setFillAfter(true); halfWidth = width / 2; halfHeight = height / 2; setInterpolator(new LinearInterpolator()); } // 設定旋轉角度 public void setRotateY(float rorateY) { mRotateY = rorateY; } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { final Matrix matrix = t.getMatrix(); mCamera.save(); // 使用Camera設定旋轉的角度 mCamera.rotateY(mRotateY * interpolatedTime); // 將旋轉變換應用到matrix上 mCamera.getMatrix(matrix); mCamera.restore(); // 在變換前,將動畫的中心點從預設的(0,0)移動(0, -halfHeight) matrix.preTranslate(0, -halfHeight); // 變換後再從(-halfWidth, -halfHeight)移動halfWidth,halfHeight,使之再次回到(0,0) matrix.postTranslate(0, halfHeight); // View view; }}
使用代碼 :
Button btn = new Button(MainActivity.this) ; btn.setText("RotateY"); MyAnimation animation = new MyAnimation(); animation.setRotateY(45f); animation.setDuration(2000);// 啟動動畫 btn.startAnimation(animation); 效果 (中的view並不是button,是我另外例子中的view):
android View設定隱藏動畫問題
mAppHiddenAction.setDuration(400);
mAppGridView.startAnimation(mHiddenAction);
scrollView.startAnimation(mAppHiddenAction);
relativelayout.startAnimation(mAppHiddenAction);
後面這些代碼應該在mAppHiddenAction結束後再執行,而不是直接在這就執行,你可用hander+定時器延後執行即可
scrollView.setVisibility(View.GONE);
mAppGridView.setVisibility(View.GONE);
tv.setVisibility(View.GONE);
btn_save.setVisibility(View.GONE);
android 動畫效果
xml中設定fillAfter=true