Android動畫可以分3種:View動畫,幀動畫和屬性動畫;屬性動畫為API11的新特性,在低版本是無法直接使用屬性動畫的。
本章主要學(xué)習(xí)內(nèi)容:
- View動畫以及自定義View動畫。
- View動畫的一些特殊使用場景。
- 對屬性動畫做了一個(gè)全面的介紹。
- 使用動畫的一些注意事項(xiàng)。
7.1 View動畫
- View動畫的四種變換效果對應(yīng)著Animation的四個(gè)子類:TranslateAnimation(平移動畫)、ScaleAnimation(縮放動畫)、RotateAnimation(旋轉(zhuǎn)動畫)和AlphaAnimation(透明度動畫),他們即可以用代碼來動態(tài)創(chuàng)建也可以用XML來定義,推薦使用可讀性更好的XML來定義。
- <set>標(biāo)簽表示動畫集合,對應(yīng)AnimationSet類,它可以包含若干個(gè)動畫,并且他的內(nèi)部也可以嵌套其他動畫集合。android:interpolator 表示動畫集合所采用的插值器,插值器影響動畫速度,比如非勻速動畫就需要通過插值器來控制動畫的播放過程。
android:shareInterpolator表示集合中的動畫是否和集合共享同一個(gè)插值器,如果集合不指定插值器,那么子動畫就需要單獨(dú)指定所需的插值器或默認(rèn)值。 - Animation通過setAnimationListener方法可以給View動畫添加過程監(jiān)聽。
- 自定義View動畫只需要繼承Animation這個(gè)抽象類,并重寫initialize和applyTransformation方法,在initialize方法中做一些初始化工作,在applyTransformation中進(jìn)行相應(yīng)的矩形變換,很多時(shí)候需要采用Camera來簡化矩形變換過程。
- 幀動畫是順序播放一組預(yù)先定義好的圖片,類似電影播放;使用簡單但容易引發(fā)OOM,盡量避免使用過多尺寸較大的圖片。
7.2 View動畫的特殊使用場景
- LayoutAnimation作用于ViewGroup,為ViewGroup指定一個(gè)動畫,當(dāng)他的子元素出場的時(shí)候都會具有這種動畫,ListView上用的多,LayoutAnimation也是一個(gè)View動畫。
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animationOrder="normal"
android:delay="0.3" android:animation="@anim/anim_item"/>
//--- delay 表示動畫開始的時(shí)間延遲,比如子元素入場動畫的時(shí)間周期為300ms,
//那么0.5表示每個(gè)子元素都需要延遲150ms才開始播放入場動畫。
//--- animationOrder 表示子元素的動畫的順序,有三種選項(xiàng):
//normal(順序顯示)、reverse(逆序顯示)和random(隨機(jī)顯示)。
//---1. android:animation 為子元素指定具體的入場動畫
//----------------------
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:shareInterpolator="true">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0" />
<translate
android:fromXDelta="300"
android:toXDelta="0" />
</set>
使用LayoutAnimation
//--- 第一種方法、為需要的ViewGroup指定android:layoutAnimation屬性
//---這樣ViewGroup的子View就有出場動畫了
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layoutAnimation="@anim/anim_layout"/>
//
//--- 第二種方法、通過LayoutAnimationController來實(shí)現(xiàn)
Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
listview.setLayoutAnimation(controller);
- Activity/Fragment的切換效果
在startActivity(Intent)或finish()之后調(diào)用overridePendingTransition(int enterAnim,int exitAnim)方法。
Fragment也可以添加切換動畫,通過FragmentTransaction中的
setCustomAnimations()方法來添加;需考慮兼容性使用View動畫,屬性動畫是API11新引入的;
7.3屬性動畫
- 屬性動畫可以對任意對象的屬性進(jìn)行動畫而不僅僅是View,動畫默認(rèn)間隔300ms,默認(rèn)幀率10ms/幀。在一個(gè)時(shí)間間隔內(nèi)完成對象從一個(gè)屬性值到另一個(gè)屬性值的改變。
- android:propertyName 表示屬性動畫的作用的屬性的名稱 。
android:duration 表示動畫的時(shí)長。
android:valueFrom 表示動畫的起始值。
android:valueTo 表示屬性的結(jié)束值。
android:startOffset 表示動畫的延遲時(shí)間,當(dāng)動畫開始后,需要延遲多少毫秒才會真正播放此動畫。
android:repeatCount 表示動畫的重復(fù)次數(shù)(默認(rèn)為0,其中-1表示無線循環(huán))。
android:repeatMode 表示動畫的重復(fù)模式 (repeat和reverse可選,表示連續(xù)重復(fù)和逆向重復(fù)(第一次播放完之后,第二次倒著播,第三次重頭開始播,第四次倒著播))。
android:valueType 表示android:propertyName所指定的屬性的類型,可選intType/floatType;
如果android:propertyName指定的屬性表示顏色,則不需要指定該屬性。 - 實(shí)際開發(fā)中建議使用代碼來實(shí)現(xiàn)屬性動畫,代碼來實(shí)現(xiàn)比較簡單,而且很多時(shí)候一個(gè)熟悉的初始值無法提前知道,需在代碼中動態(tài)獲取。
7.3.2 理解插值器和估值器
- 時(shí)間插值器(TimeInterpolator)的作用是根據(jù)時(shí)間流逝的百分比來計(jì)算出當(dāng)前屬性值改變的百分比,系統(tǒng)預(yù)置的有LinearInterpolator(線性插值器:勻速動畫),AccelerateDecelerateInterpolator(加速減速插值器:動畫兩頭慢中間快),DecelerateInterpolator(減速插值器:動畫越來越慢)。
- 估值器(TypeEvaluator)的作用是根據(jù)當(dāng)前屬性改變的百分比來計(jì)算改變后的屬性值。系統(tǒng)預(yù)置有IntEvaluator 、FloatEvaluator 、ArgbEvaluator。
//整形估值器源碼
/**
* @param fraction 表示開始和結(jié)束值之間的比例
* @param startValue 開始值
* @param endValue 結(jié)束值
* @return
*/
public class IntEvaluator implements TypeEvaluator<Integer> {
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}
- 插值器和估值器除了系統(tǒng)提供之外,我們還可以自定義。自定義插值器需要實(shí)現(xiàn)Interpolator或者TimeInterpolator;自定義估值器算法需要實(shí)現(xiàn)TypeEvaluator。
7.3.3屬性動畫的監(jiān)聽器
public static interface AnimatorListener {
void onAnimationStart(Animator animation); //動畫開始
void onAnimationEnd(Animator animation); //動畫結(jié)束
void onAnimationCancel(Animator animation); //動畫取消
void onAnimationRepeat(Animator animation); //動畫重復(fù)播放
}
- 為了方便開發(fā),系統(tǒng)提供了AnimatorListenerAdapter類,它是AnimatorListener的適配器類,可以有選擇的實(shí)現(xiàn)以上4個(gè)方法。
- AnimatorUpdateListener會監(jiān)聽整個(gè)動畫的過程,動畫由許多幀組成的,每播放一幀,onAnimationUpdate就會調(diào)用一次。
7.3.4 對任意屬性做動畫
- 屬性動畫要求作用的對象提供該屬性的get和set方法,缺一不可。
- 如果你的對象沒有對應(yīng)的get和set方法
- 請給你的對象加上get和set方法,如果你有權(quán)限的話(如果直接使用系統(tǒng)的類,是無法加上的);
- 用一個(gè)類來包裝原始對象,間接為其提供get和set方法;
//包裝View類 用于給屬性動畫調(diào)用 從而包裝了set get
public class ViewWrapper {
private View target;
public ViewWrapper(View target) {
this.target = target;
}
public int getWidth() {
return target.getLayoutParams().width;
}
public void setWidth(int width) {
target.getLayoutParams().width = width;
target.requestLayout();
}
}
- 采用ValueAnimator,監(jiān)聽動畫過程,自己實(shí)現(xiàn)屬性的改變;
/** 使用ValueAnimator 監(jiān)聽動畫過程 自己實(shí)現(xiàn)屬性改變
*
* @param target 作用的View
* @param start 動畫起始值
* @param end 動畫終止值
*/
private void startValueAnimator(final View target, final int start, final int end) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
private IntEvaluator mEvaluation = new IntEvaluator();//新建一個(gè)整形估值起 方便估值使用
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//獲得當(dāng)前動畫的進(jìn)度值 1~100之間
int currentValue = (int) animation.getAnimatedValue();
Log.e("Anim", "currentValue: " + currentValue);
//獲得當(dāng)前進(jìn)度占整個(gè)動畫過程的比例,浮點(diǎn)型,0~1之間
float fraction = animation.getAnimatedFraction();
//調(diào)用估值器,通過比例計(jì)算出寬度 ,再設(shè)置給Button
int targetWidth = mEvaluation.evaluate(fraction, start, end);
target.getLayoutParams().width = targetWidth;
target.requestLayout();
}
});
}
7.3.5 屬性動畫的工作原理
通過反射調(diào)用get/set方法;屬性動畫需要運(yùn)行在有Looper的線程中。
7.4 使用動畫的注意事項(xiàng)
- 使用幀動畫時(shí),當(dāng)圖片數(shù)量較多且圖片分辨率較大的時(shí)候容易出現(xiàn)OOM,需注意,盡量避免使用幀動畫。
- 使用無限循環(huán)的屬性動畫時(shí),在Activity退出時(shí)及時(shí)停止,否則將導(dǎo)致Activity無法釋放從而造成內(nèi)存泄露。
- View動畫是對View的影像做動畫,并不是真正的改變了View的狀態(tài),因此有時(shí)候會出現(xiàn)動畫完成后View無法隱藏(setVisibility(View.GONE)失效),這時(shí)候調(diào)用view.clearAnimation()清理View動畫即可解決。
- 不要使用px,使用px會導(dǎo)致不同設(shè)備上有不同的效果。
- View動畫是對View的影像做動畫,View的真實(shí)位置沒有變動,也就導(dǎo)致點(diǎn)擊View動畫后的位置觸摸事件不會響應(yīng),屬性動畫不存在這個(gè)問題。
- 使用動畫的過程中,使用硬件加速可以提高動畫的流暢度。
- 動畫在3.0以下的系統(tǒng)存在兼容性問題,特殊場景可能無法正常工作,需做好適配工作。