Android中的動畫總結

文章主要內容來源《Android開發藝術探索》,部份內容來源網上的文章,文中會有連接。android

Android系統提供了兩個動畫框架:屬性動畫框架和View動畫框架。 兩個動畫框架都是可行的選項,可是屬性動畫框架一般是首選的使用方法,由於它更靈活,並提供更多的功能。 除了這兩個框架,還可使用Drawable動畫(即逐幀動畫,AnimationDrawable),它容許你加載Drawable資源並逐幀地顯示它們。算法

  1. View動畫框架(補間動畫)
    View動畫框架中一共提供了AlphaAnimation(透明度動畫)、RotateAnimation(旋轉動畫)、ScaleAnimation(縮放動畫)、TranslateAnimation(平移動畫)四種類型的補間動畫;而且View動畫框架還提供了動畫集合類(AnimationSet),經過動畫集合類(AnimationSet)能夠將多個補間動畫以組合的形式顯示出來。補間動畫的實現,通常會採用xml文件的形式,那樣代碼會更容易書寫和閱讀,同時也更容易複用。框架

  2. 屬性動畫框架
    與屬性動畫相比View動畫存在一個缺陷,View動畫改變的只是View的顯示,而沒有改變View的響應區域,而且View動畫只能對View作四種類型的補間動畫。所以Google在Android3.0(API級別11)及其後續版本中添加了屬性動畫框架,從名稱中就能夠知道只要某個類具備屬性(即該類含有某個字段的set和get方法),那麼屬性動畫框架就能夠對該類的對象進行動畫操做(其實就是經過反射技術來獲取和執行屬性的get,set方法),一樣屬性動畫框架還提供了動畫集合類(AnimatorSet),經過動畫集合類(AnimatorSet)能夠將多個屬性動畫以組合的形式顯示出來。dom

做者:ForeverCy
連接:http://www.jianshu.com/p/b117c974deaf
來源:簡書
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。ide


1、View動畫

View動畫的四種變換效果對應着Animation的四個子類:TranslateAnimation、ScaleAnimation、RotateAnimation、AlphaAnimation。四種動畫能夠用這四個類經過代碼實現,也可使用XML文件來定義。建議使用XML來定義動畫,由於XML格式可讀性好並且方便複用。oop

名稱 標籤 子類
平移動畫 TranslateAnimation
縮放動畫 ScaleAnimation
選中動畫 RotateAnimation
透明度動畫 AlphaAnimation
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator=""
    android:shareInterpolator="true|false">
    <translate
        android:fromXDelta=""
        android:toXDelta=""
        android:fromYDelta=""
        android:toYDelta="" />
    <scale
        android:fromXScale=""
        android:toXScale=""
        android:fromYScale=""
        android:toYScale=""
        android:pivotX=""
        android:pivotY="" />
    <rotate
        android:fromDegrees=""
        android:toDegrees=""
        android:pivotX=""
        android:pivotY="" />
    <alpha
        android:fromAlpha=""
        android:toAlpha="" />
    
    <set>
        <!--set嵌套set-->
    </set>
</set>

View動畫能夠是單個動畫,也能夠由一系列動畫組成,使用 標籤實現組合。 標籤對應AnimationSet類,內部也能夠嵌套其餘動畫集合。 動畫

android:interpolator表示動畫集合所使用的插值器,插值器影響動畫的速度,好比非勻速動畫就須要經過插值器來控制動畫的播放過程。這個屬性能夠不指定,默認是@android:anim/accelerate_decelerate_interpolator,即加速減速插值器。
android:shareInterpolator表示集合中的動畫是否和集合共享同一個插值器。若是集合不指定插值器,那麼子動畫就須要單獨指定所須要的插值器或者使用默認值。lua

android:fromXDelta x的起始值
android:toXDelta x的結束值
android:fromYDelta y的起始值
android:toYDelta y的結束值.net

android:fromXScale 水平方向縮放的起始值
android:toXScale 水平方向縮放的結束值
android:fromYScale 豎直方向縮放的起始值
android:toYScale 豎直方向縮放的結束值
android:pivotX 縮放的軸點的x座標
android:pivotY 縮放的軸點的y座標線程

android:fromDegrees 旋轉開始的角度
android:toDegrees 旋轉結束的角度
android:pivotX 旋轉的軸點的x座標
android:pivotY 選中的軸點的y座標

android:fromAlpha 透明度的起始值
android:toAlpha 透明度的結束值

一些其餘經常使用屬性

android:duration 動畫的持續時間
android:fillBefore 動畫結束後是否回到執行前的位置
android:fillAfter 動畫結束後是否停留在結束位置
android:interpolator 動畫使用的插值器
android:startOffset 動畫執行以前的等待時間
android:repeatCount 動畫重複執行的次數
xml屬性都有對應的set方法

使用示例

首先編寫動畫xml文件test_anim.xml

Button mButton = (Button)findViewById(R.id.button);
Animation animation = AnimationUtils.loadAnimation(context, R.anim.test_anim);
mButton.startAnimation(animation);

也能夠經過代碼實現

AlphaAnimation animation = new AlphaAnimation(0, 1);
animation.setDuration(300);
mButton.startAnimation(animation);

使用setAnimationListener方法能夠給動畫添加過程監聽。

View動畫的特殊使用場景

LayoutAnimation控制ViewGroup的子View的出場效果,使用步驟以下:
  1. 定義LayoutAnimation,文件名res/anim/anim_layout.xml
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" 
    android:delay="150"
    android:animationOrder="normal"
    android:animation="@anim/anim_item"/>

android:delay 子元素開始動畫的時間延遲
android:animationOrder 子元素動畫的順序。有normal(順序)、reverse(逆向)、random(隨機)三種順序。
android:animation 子元素入場的具體動畫

  1. 定義子元素具體的入場動畫,文件名res/anim/anim_item.xml
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="500"
    android:toXDelta="0"/>
  1. 爲Viewgroup指定 android:layoutAnimation屬性,好比ListView:
<ListView
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layoutAnimation="@anim/anim_layout" />

除了經過xml中指定layoutAnimation屬性,也能夠經過LayoutAnimationController來實現:

Animation animation = AnimationUtils.loadAnimation(context, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
listView.setLayoutAnimation(controller);
Activity的切換效果

使用overridePendingTransition(int enterAnim, int exitAnim)方法實現Activity的切換動畫,這個方法必須在startActivity()或者finish()以後調用才能生效。
Fragment也能夠添加切換動畫,經過FragmentTransaction中的setCustomAnimations()方法實現。



2、幀動畫

幀動畫的標籤是 ,對應AnimationDrawable類。
示例代碼

<animation-list xmlns:android="http://schemas.android.com/apk/res/android" 
    android:oneshot="false">
    <item android:drawable="@drawable/img1" android:duration="500"/>
    <item android:drawable="@drawable/img2" android:duration="500"/>
    <item android:drawable="@drawable/img3" android:duration="500"/>
</animation-list>
Button mButton = (Button)findViewById(R.id.button1);
mButton.setBackgroundResource(R.drawable.frame_animation);
AnimationDrawable drawable = (AnimationDrawable)mButton.getBackground();
drawable.start();

注意幀動畫容易引發OOM。



3、屬性動畫

屬性動畫從 API 11 纔有,屬性動畫能夠對任意對象的屬性進行動畫而不只僅是View,達到的效果是:在一個時間間隔內完成對象從一個屬性值到另外一個屬性值的改變。屬性動畫經常使用的動畫類:ValueAnimator、ObjectAnimator、AnimatorSet。ObjectAnimator繼承自ValueAnimator,AnimatorSet是動畫集合。
屬性動畫也有對應的xml標籤,可是建議使用代碼來實現屬性動畫,由於使用代碼比xml簡單。並且不少時候一個屬性的起始值沒法提早肯定。

一、經過幾個例子看如何使用屬性動畫:

  1. 改變對象myObject的translationY屬性,讓其沿着Y軸向上平移一段距離:它的高度。該動畫在默認時間內完成
ObjectAnimator.ofFloat(myObject, "translationY", -myObject.getHeight()).start();
  1. 改變一個對象的背景色屬性,讓背景色在3秒內從 0xFFFF8080 到 0xFF8080FF 的漸變,動畫會無限循環並且會有反轉效果
ValueAnimator anim = ObjectAnimator.ofInt(myObject, "backgroundColor",0xFFFF8080,0xFF8080FF);
anim.setDuration(3000);
anim.setEvaluator(new ArgbEvaluator());
anim.setRepeatCount(ValueAnimator.INFINITE);
anim.setRepeatMode(ValueAnimator.REVERSE);
anim.start();
  1. 動畫集合,5秒內對View的旋轉,平移,縮放和透明都進行改變。
AnimatorSet set = new AnimatorSet();
set.playTogether(
        ObjectAnimator.ofFloat(myView, "rotationX", 0, 360),
        ObjectAnimator.ofFloat(myView, "rotationY", 0, 180),
        ObjectAnimator.ofFloat(myView, "rotation", 0, -90),
        ObjectAnimator.ofFloat(myView, "translationX", 0, 90),
        ObjectAnimator.ofFloat(myView, "translationY", 0, 90),
        ObjectAnimator.ofFloat(myView, "scaleX", 1, 1.5f),
        ObjectAnimator.ofFloat(myView, "scaleY", 1, 0.5f),
        ObjectAnimator.ofFloat(myView, "alpha", 1, 0.25f, 1)
);
set.setDuration(5*1000).start();

二、上面的代碼總結

上面代碼用到一個主要的方法
ObjectAnimator.ofFloat(target, propertyName, values...);

target 是動畫目標,任何對象,不必定必須是View
propertyName 是屬性名字
values 是可變參數, 從v1變化到v2到vn。。。

例子:
mIv是一個imageView
//alpha 從0 到1 的動畫
ObjectAnimator.ofFloat(mIv, "alpha", 0f,1f)
.setDuration(500)
.start();
若是要實現其餘效果,修改propertyName和values就好了。

屬性動畫的原理就是經過反射,以動畫的效果屢次調用set方法來改變屬性值的。因此,使用屬性動畫時,相應的對象屬性必須有set方法,get方法能夠沒有,可是若是使用動畫的時候沒有傳遞初始值,就必須提供get方法,由於系統要經過get方法獲取屬性的默認初始值。

在屬性動畫中,View的經常使用屬性

alpha 透明度
rotation z軸旋轉
rotationX x軸旋轉
rotationY y軸旋轉
translationX x水平偏移
translationY y水平偏移
ScaleX x軸縮放
ScaleY y軸縮放

三、插值器和估值器

插值器(TimeInterpolator/Interpolator)用來修飾動畫效果,定義動畫的變化規率(變化趨勢),好比平移動畫,能夠勻速平移也能夠加速平移,這個由插值器決定。
估值器(Evaluator)用來決定具體的數值變化,好比(勻)加速平移時,「加速度」是多少由估值器決定。

插值器TimeInterpolator和Interpolator,後者是繼承前者的接口。
TimeInterpolator接口是屬性動畫中新增的,用於兼容Interpolator接口,這使得全部過去的Interpolator實現類均可以直接在屬性動畫使用。
出自:http://blog.csdn.net/carson_ho/article/details/72863901

系統內置的插值器有如下幾種:
  • AccelerateInterpolator 加速
  • DecelerateInterpolator 減速
  • LinearInterpolator 勻速
  • AccelerateDecelerateInterpolator 先加速再減速(在動畫開始與結束的地方速率改變比較慢,在中間的時候最快)
  • AnticipateInterpolator 開始的時候向後而後向前甩(先退後再加速前進)
  • AnticipateOvershootInterpolator 開始的時候向後而後向前甩必定值後返回最後的值(先退後再加速前進,超出終點後再回終點)
  • BounceInterpolator 動畫結束的時候彈起(最後階段彈球效果)
  • CycleInterpolator 動畫循環播放特定的次數,速率改變沿着正弦曲線
  • OvershootInterpolator 向前甩必定值後再回到原來位置(快速完成動畫,超出再回到結束時的位置)
    以上每種插值器都有對應的xml資源,好比:@android:anim/linear_interpolator。(注意資源名的規律)
系統內置的估值器有如下三種:

IntEvaluator 以整型的形式從初始值到結束值 進行過渡
FloatEvaluator 以浮點型的形式從初始值到結束值 進行過渡
ArgbEvaluator 以Argb類型的形式從初始值到結束值 進行過渡

若是系統內置的插值器和估值器沒法知足需求,也能夠自定義。
View動畫的插值器實現Interpolator接口,View動畫沒有估值器
屬性動畫的插值器實現實現TimeInterpolator接口,估值器實現TypeEvaluator接口
自定義插值器和估值器參考系統內置的插值器和估值器便可。

如下摘自http://blog.csdn.net/carson_ho/article/details/72863901
實現Interpolator接口自定義插值器的說明(TimeInterpolator接口相同)

public interface Interpolator {  
    // 內部只有一個方法
    float getInterpolation(float input) {  
       // 參數說明
       // input值值變化範圍是0-1,且隨着動畫進度(0% - 100% )均勻變化
       // 即動畫開始時,input值 = 0;動畫結束時input = 1
       // 而中間的值則是隨着動畫的進度(0% - 100%)在0到1之間均勻增長
   
       ...// 插值器的計算邏輯
   
       return xxx;
       // 返回的值就是用於估值器繼續計算的fraction值
    }
}

實現TypeEvaluator接口自定義估值器的說明

public interface TypeEvaluator {  

    public Object evaluate(float fraction, Object startValue, Object endValue) {  
        // 參數說明
        // fraction:插值器getInterpolation()的返回值
        // startValue:動畫的初始值
        // endValue:動畫的結束值

        ....// 估值器的計算邏輯

        return xxx;
        // 賦給動畫屬性的具體數值
        // 使用反射機制改變屬性變化

        // 特別注意
        // 插值器的input值 和 估值器fraction有什麼關係呢?
        // 答:input的值決定了fraction的值:input值通過計算後傳入到插值器的getInterpolation()
        // 而後經過實現getInterpolation()中的邏輯算法,根據input值來計算出一個返回值,而這個返回值就是fraction了
    }  
}
如何使用插值器和估值器

View動畫和屬性動畫均可以使用插值器,估值器只有屬性動畫能夠用。

插值器用法

// 步驟1:建立須要設置動畫的視圖View
Button mButton = (Button) findViewById(R.id.Button);
// 步驟2:建立透明度動畫的對象 & 設置動畫效果
Animation alphaAnimation = new AlphaAnimation(1,0);     
alphaAnimation.setDuration(3000);
// 步驟3:建立對應的插值器類對象
Interpolator overshootInterpolator = new OvershootInterpolator();
// 步驟4:給動畫設置插值器
alphaAnimation.setInterpolator(overshootInterpolator);
// 步驟5:播放動畫
mButton.startAnimation(alphaAnimation);

估值器用法

// 在第3個參數中傳入對應估值器類的對象
ObjectAnimator anim = ObjectAnimator.ofObject(myView2, "height", new Evaluator(),1,3);

四、屬性動畫的監聽

有兩個監聽接口AnimatorListener和AnimatorUpdateListener。AnimatorListener和View動畫的AnimationListener相似,能夠監聽動畫的開始、結束等過程。AnimatorUpdateListener能夠監聽動畫的每一幀變化,動畫每變化一幀,接口裏的方法被調用一次。



4、動畫相關的其餘問題、知識、技巧

對於沒有set和get方法的對象如何使用屬性動畫:
  1. 給對象加上相應的set和get方法,若是有權限的話(對系統的View是沒有權限改源碼的)
  2. 用一個包裝類包裝原始對象,間接的提供set和get方法
  3. 使用ValueAnimator,監聽動畫過程,本身實現屬性的改變。ValueAnimator自己不做用於任何對象,直接使用它是沒有效果的。它能夠對一個值作動畫,能夠監聽其動畫過程,在動畫過程當中本身實現修改對象的屬性值,也就至關於對象作了動畫,示例代碼以下:
private void performAnimate(final View button, final int start, final int end) {

    ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);

    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

        //持有一個IntEvaluator對象,方便下面估值的時候使用
        private IntEvaluator mIntEvaluator = new IntEvaluator();

        @Override
        public void onAnimationUpdate(ValueAnimator animator) {
            //得到當前動畫的進度值,整型1-100之間
            int currentValue = (int) animator.getAnimatedValue();

            //得到當前進度佔整個動畫過程的比例,浮點型,0-1之間
            float fraction = animator.getAnimatedFraction();
            //直接調用整型估值器,經過比例計算出寬度,而後設給Button
            button.getLayoutParams().width = mIntEvaluator.evaluate(fraction, start, end);
            button.requestLayout();
        }
    });
    valueAnimator.setDuration(5000).start();
}

@Override
public void onClick(View v) {
    if (v == mButton) {
        performAnimate(mButton, mButton.getWidth(), 500);
    }
}
經過源碼能夠看出,屬性動畫須要運行在有Looper的線程中
使用動畫的注意事項
  1. OOM問題。主要是幀動畫圖片數量較多且圖片較大時容易出現OOM。
  2. 內存泄漏。在屬性動畫中有一類無限循環的動畫,這類動畫須要在Activity退出時及時中止,不然將致使Activity沒法釋放從而形成內存泄漏。經過驗證後發現View動畫不存在此問題。
  3. 兼容性問題。動畫在3.0如下的系統上有兼容性問題,須要作好適配。
  4. View動畫問題。View動畫是對View的影像作動畫,並不會真正的改變View的狀態。若是出現動畫完成後View沒法隱藏,即setVisibility(View.GONE)失效,這個時候只要調用view.clearAnimation()清除View動畫便可解決。
  5. 不要使用px。儘可能使用dp,使用px會致使在不一樣設備上有不一樣的效果。
  6. View平移後:在3.0之前的系統,View動畫和屬性動畫都是新位置沒法點擊,老位置能夠點擊;3.0之後(包括3.0),屬性動畫的點擊事件觸發位置是位移後的位置,View動畫是原位置。
  7. 開啓硬件加速能夠提升動畫的流暢性。



5、補充屬性動畫

View動畫能夠設置ViewGroup的子View的出場動畫,屬性動畫能夠爲ViewGroup的子View的顯示和隱藏設置過渡動畫。出場動畫文中已經介紹,屬性動畫實現的過分動畫詳細見ForeverCy的文章Android中的View動畫和屬性動畫 中的相關部分。

相關文章
相關標籤/搜索