Android學習筆記: Android動畫特效
Android動畫特效
Android應用中各式各樣的互動介面能體現一個Android應用獨特的設計理念,為應用增色不少。為了要實現這些效果就需要用到Android中關於動畫的API,Android中的動畫效果主要分為逐幀動畫
、補間動畫
、屬性動畫
。
逐幀動畫(FramAnimation)
逐幀動畫的原理與電影的原理一樣,都是把一連串的靜態圖片按順序依次顯示,利用“視覺暫留”使人感覺“動畫”的錯覺。
AnimationDrawable
逐幀動畫一般採用AnimationDrawable顯示,並用XML檔案定義資源
<?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/image1" android:duration="60"/> <item android:drawable="@drawable/image2" android:duration="60"/> <item android:drawable="@drawable/image3" android:duration="60"/> <item android:drawable="@drawable/image4" android:duration="60"/> …………… <item android:drawable="@drawable/image9" android:duration="60"/> </animation-list>
定義的資源可以作為ImageView的資原始檔使用:
ImageView image = (ImageView) findViewById(R.id.frame_animation); //獲取在佈局檔案中設定的動畫檔案 final AnimationDrawable anim = (AnimationDrawable)image.getDrawable(); //為ImageView設定點選事件,點選開始動畫,再次點選停止動畫 image.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(anim.isRunning()) { anim.stop(); } else { anim.start(); } } });
如果不使用XML檔案定義資源,也可以通過在JAVA程式碼中建立AnimationDrawable類,呼叫addFrame(Drawable
frame, int duration)
新增每一幀。
逐幀動畫效果:
補間動畫(TweenAnimation)
補間動畫是隻需指定開始狀態與結束狀態的“關鍵幀”,由系統根據配置計算出中間幀的一種動畫。其本質上也是逐幀動畫,只是不需要指定每一幀。Android使用Animation代表抽象的動畫類,它包括如下幾個子類:
- AlphaAnimation: 透明度改變的動畫。需指定開始與結束時的透明度,變化由0到1。
- ScaleAnimation: 縮放大小的動畫。需指定開始與結束時以X、Y軸的縮放參數的縮放比,還可以指定縮放中心的座標pivotX、pivotY。
- TranslateAnimation: 位移動畫。需指定開始與結束位置的X、Y座標。
- RotateAnimation: 旋轉動畫。需指定開始與結束的旋轉角度,旋轉中心軸pivotX、pivotY。
Animation都需要指定動畫持續時間。
//以圖片中心為基準3秒內旋轉9000度
RotateAnimation anim = new RotateAnimation(9000, 0, image.getWidth() / 2, image.getHeight() / 2);
anim.setDuration(3000);
image.setAnimation(anim);
//透明度由0到1
lphaAnimation anim = new AlphaAnimation(0, 1);
//由1倍縮放到3倍
ScaleAnimation anim = new ScaleAnimation(1, 3, 1, 3, image.getWidth() / 2, image.getHeight() / 2);
//從(0, 0)移動到(300, 300)
TranslateAnimation anim = new TranslateAnimation(0, 300, 0, 300);
為了控制系統在關鍵幀之間需要補入多少幀,具體在動畫執行時何時補入,需要藉助Interpolator
。
Interpolator根據特定演算法計算出整個動畫所需動態插入幀的密度和位置,控制動畫的變化速度,如勻速變化、加速、減速、拋物線速度等。Interpolator為一個介面,它的實現類有:
- LinearInterpolator: 使動畫均勻的速度改變
- AccelerateInterpolator: 是動畫在開始的地方改變速度較慢,然後開始加速。
- AccelerateDecelerateInterpolator: 在動畫開始、結束的地方速度變慢,在中間的時候加速。
- CycleInterpolator: 動畫迴圈播放特定的次數,變化速度按正弦曲線改變。
- DecelerateInterpolator: 在動畫開始的地方改變速度較塊,然後開始減速。
補間動畫一般在XML檔案中用元素定義(可混合多種動畫),並在JAVA程式碼中用AnimationUtils.loadAnimation(Context
context, int Id)
載入自定義補間動畫。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
>
<!-- 以中心旋轉3000度,持續1秒 -->
<rotate
android:fromDegrees="3000"
android:toDegrees="0"
android:duration="1000"
android:pivotX="50%"
android:pivotY="50%"
android:interpolator="@android:anim/accelerate_interpolator"
/>
<!-- 1秒內變透明,startOffset屬性為500毫秒後執行動畫 -->
<alpha
android:fromAlpha="1"
android:toAlpha="0.1"
android:duration="1000"
android:interpolator="@android:anim/linear_interpolator"
android:startOffset="500"
/>
<!-- 1秒內放大3倍,500毫秒後開始 -->
<scale
android:fromXScale="1"
android:toXScale="3"
android:fromYScale="1"
android:toYScale="3"
android:pivotX="50%"
android:pivotY="50%"
android:duration="1000"
android:startOffset="500"
android:interpolator="@android:anim/linear_interpolator"
/>
</set>
補間動畫效果:
自定義補間動畫
自定義補間動畫需繼承Animation類,並重寫該類的 applyTransformation(float interpolatedTime,
Transformation t)
方法,其中引數說明如下:
- interpolatedTime: 動畫時間進行比。不管動畫實際持續時間如何,當動畫播放時,該引數總是自動從0 變化到1的。
- Transformation: 該引數代表了補間動畫在不同時刻對圖形或元件的變形程度。Transformation代表了對圖片或檢視的變形,該物件裡封裝了一個Matrix物件,對它所包裝的Matrix進行位移、傾斜、旋轉等變換時,Transformation將會控制對應的圖片或檢視進行相應的變換。
為了控制圖片或View進行三維空間的變換,還需要藉助於Android提供一個Camera,Camera提供瞭如下常用方法:
- getMatrix(Matrix matrix): 將Camera所做的變換應用到指定的matrix上
- rotateX(float deg):將目標元件沿X軸旋轉
- rotateY(float deg):將目標元件沿Y軸旋轉
- rotateZ(float deg):將目標元件沿Z軸旋轉
- translate(float x, float y, float z): 把目標元件在三維空間裡進行位移變換
- applyToCanvas(Canvas canvas):把Camera所做的變換應用到Canvas上。
實現一個沿X軸旋轉的自定義補間動畫,其方法如下:
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
// TODO Auto-generated method stub
//camera儲存初始狀態
camera.save();
//繞X軸旋轉
camera.rotateX(1000 * interpolatedTime);
//從Transformation獲得Matrix
Matrix matrix = t.getMatrix();
//將變換應用到matrix上
camera.getMatrix(matrix);
//camera恢復初始狀態
camera.restore();
}
自定義補間效果:
屬性動畫(只支援API11及以上)
若要在API11之前的版本使用屬性動畫,可以呼叫Nine Old Androids開源庫,使用方法與官方API一樣,只是匯入的包不同。
增強版補間動畫,幾乎可以定義任何屬性變化,以及對任何物件執行動畫(不管是否顯示在螢幕上),屬性動畫需要定義的屬性有:
- 動畫持續時間(android:duration)預設屬性300毫秒
- 動畫插值方式(android:interpolator)控制補入幀
- 動畫重複次數(android:repeatCount)
- 重複行為(android:repeatMode)指定動畫結束,重複下次動畫時,是從開始幀播放到結束幀,還是從結束幀播放到開始幀
- 動畫集()將多個屬性動畫合併成一組,既可以讓這組屬性動畫按次序播放,也可以讓這組屬性動畫同時播放。在屬性動畫資原始檔中通過元素來組合,該元素的android:ordering屬性指定該組動畫是按次序播放的,還是同步播放。
- 幀重新整理率()指定每隔多長時間播放一幀。預設為10毫秒
屬性動畫API
- Animator : 屬性動畫的基類,基本上被用於繼承並重寫它的相關方法。
- ValueAnimator : Animatior的子類,屬性動畫主要的時間引擎,它負責計算各個幀的屬性值。它定義了屬性動畫的絕大部分的核心功能,包括計算各幀的相關屬性值,負責處理更新事件。按屬性值的型別控制計算規則。屬性動畫主要由兩方面組成:1.計算各幀的相關屬性值;2.為指定的物件設定這些計算後的值。ValueAnimator只負責第一方面的內容,因此程式必須根據ValueAnimator計算並監聽值更新來更新物件的相關屬性。
- ObjectAnimator : 它是ValueAnimator子類,允許程式設計師對指定物件的屬性執行動畫。實際應用中,ObjectAnimator使用起來更加簡單,因此更加常用,少數場景下,由於ObjectAnimator存在一些限制,需要考慮使用ValueAnimator
- AnimatorSet : 他是Animatior的子類,用於組合多個Animator,並指定多個Animator是按次序播放,還是同時播放
要使用屬性動畫還需使用一個Evaluator,該工具類控制屬性動畫如何計算屬性值。Android提供瞭如下Evaluator:
- IntEvaluator: 用於計算int型別屬性值的計算器
- FloatEvaluator: 計算float型別屬性值
- ArgbEvaluator: 計算以十六進位制表示的顏色的計算器
- TypeEvaluator: 計算器介面,可以通過實現該介面來實現自定義計算器。
使用ValueAnimatior建立動畫:
- 呼叫ValueAnimator的onInt()、onfloat() 、ofObject()靜態方法建立ValueAnimator例項
- 呼叫ValueAnimator的setXxx()設定動畫持續時間、插值方式、重複次數等
- 呼叫start()方法啟動動畫
-
為ValueAnimator註冊AnimatorUpdateListener監聽器,在該監聽器中可以監聽ValueAnimator計算出來的值的改變,並將這些值應用到指定物件
ValueAnimator animator = ValueAnimator.ofFloat(0.1f, 1f); animator.setDuration(3000); animator.start();
上面的例子只是計算了在3000毫秒裡float的值從0.1到1的變化的值,並沒有把這些計算的值應用到任何物件上,因此也不會顯示任何動畫。
除此之外,還可以提供一個自定義的Evaluator計算器,例如:
ValueAnimator anim = ValueAnimator.ofObject(new MyTypeEvaluator(), startVal, endVal);
如果希望使用ValueAnimator建立動畫,還需要註冊一個監聽器:AnimatorUpdateListener,該監聽器負責更新物件的屬性值,實現這個監聽的時候,可以通過getAnimatiedValue()的方法來獲取當前幀的值,並將該計算出來的值應用到指定物件上。
使用ObjectAnimator建立動畫
ObjectAnimator繼承了ValueAnimator,ObjectAnimatior在建立時需要指定物件和物件屬性, 因此不需要註冊AnimatorUpdateListener。
ObjectAnimator anim = ObjectAnimator.ofFloat(foo, “alpha”, 0f, 1f);
注意事項:
- 要為指定物件的對應屬性提供setter方法,如上例中需要為foo提供setAlpha(float value)方法
- 如果呼叫ObjectAnimator的ofInt、ofFloat()等方法時values..引數只提供了一個值,則該值會被認為是結束值,而方法中的物件應該為該屬性提供一個getter方法,該getter方法返回的值將被作為開始值。
- 如果動畫物件是View,為了能顯示動畫效果,可能還需要在onAnimationUpdate()事件監聽方法中呼叫View.invalidate()方法來重新整理螢幕的顯示,比如對Drawable物件的color屬性執行動畫。但View定義的setter方法,如setAlpha()等,都會自動的呼叫invalidate()方法,因此不需要額外的呼叫invalidate()方法。
具體例子如下:
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
//過濾觸控事件,只對按下和移動事件進行響應
if(event.getAction() != MotionEvent.ACTION_DOWN &&
event.getAction() != MotionEvent.ACTION_MOVE) {
return false;
}
BitmapHolder newBmp = addBmp(event.getX(), event.getY());
float startY = newBmp.getY();
float endY = getHeight() - 15f;
float h = (float)getHeight();
float eventY = event.getY();
int duration = (int)(500 * ((h - eventY) / h));
//掉落動畫
ObjectAnimator fallAnimation = ObjectAnimator.ofFloat(newBmp, "y", startY, endY);
fallAnimation.setDuration(duration);
fallAnimation.setInterpolator(new AccelerateInterpolator());
//重複次數為1,重複模式為恢復模式,使得圖片落下後回彈
fallAnimation.setRepeatCount(1);
fallAnimation.setRepeatMode(ValueAnimator.REVERSE);
//旋轉動畫
ObjectAnimator rotateAnimation = ObjectAnimator.ofFloat(newBmp, "rotate", 8000, 0);
rotateAnimation.setDuration(duration);
rotateAnimation.setInterpolator(new AccelerateInterpolator());
rotateAnimation.setRepeatCount(1);
rotateAnimation.setRepeatMode(ValueAnimator.REVERSE);
//縮放動畫
ObjectAnimator scaleAnimation = ObjectAnimator.ofFloat(newBmp, "scale", 1, 4);
scaleAnimation.setDuration(duration);
scaleAnimation.setInterpolator(new AccelerateInterpolator());
scaleAnimation.setRepeatCount(1);
scaleAnimation.setRepeatMode(ValueAnimator.REVERSE);
//消失動畫
ObjectAnimator fadeAnimation = ObjectAnimator.ofInt(newBmp, "a", 255, 0);
fadeAnimation.setDuration(500);
fadeAnimation.setInterpolator(new AccelerateInterpolator());
//動畫集,設定動畫為同時播放
AnimatorSet animSet = new AnimatorSet();
animSet.play(fallAnimation).with(rotateAnimation);
animSet.play(rotateAnimation).with(scaleAnimation);
//監控動畫狀態,動畫完結後移除圖片
fadeAnimation.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
bmps.remove(((ObjectAnimator)animation).getTarget());
}
@Override
public void onAnimationCancel(Animator animation) {
// TODO Auto-generated method stub
}
});
//先播放圖片動畫,完成後播放消失動畫
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(fadeAnimation).after(animSet);
animatorSet.start();
return true;
}
屬性動畫效果: