Android View動畫


Android的動畫模式:tween animation,frame animation和property animation,又叫View Animation,Drawable Animation和Property Animation。前兩種是3.0曾經版本號支持的。屬性動畫是3.0之後支持的。
Animation和Animator的差異:Animation僅僅是view的繪製效果,但實際屬性沒有改變。而Animator改變的是view的屬性。比方作位移動畫。用Animation時view的實際位置沒有改變,而Animator可以改變view的位置。
本文重點介紹屬性動畫。java

1.Animation

用Animation可以實現AlphaAnimation,ScaleAnimation,TranslateAnimation,RotateAnimation。android


比方:markdown

float fromY = 0f;
        float toY = 100f;
        anim = new TranslateAnimation(0.0f, 0.0f, fromY, toY);
        anim.setInterpolator(new LinearInterpolator());
        anim.setDuration(3000);
        anim.setStartOffset(700);
        anim.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        view.startAnimation(anim);

2. TypeEvaluator

TypeEvaluator提供了一個接口,開發人員可以經過實現該接口本身定義Evaluator。ide


眼下系統提供的Evaluator有如下幾種:
ArgbEvaluator,FloatArrayEvaluator,FloatEvaluator,IntArrayEvaluator。IntEvaluator。RectEvaluator,PointFEvaluator等,
看ArgbEvaluator的實現,咱們發現僅僅需要依據咱們定義的屬性簡單的實現evaluate方法就可以了。函數

這樣咱們就可以定義本身的XXEvaluator了。
依據動畫運行的時間跟應用的Interplator,會計算出一個0~1之間的因子。即evalute函數中的fraction參數。動畫

public class ArgbEvaluator implements TypeEvaluator {
    private static final ArgbEvaluator sInstance = new ArgbEvaluator();

    public static ArgbEvaluator getInstance() {
        return sInstance;
    }

    public Object evaluate(float fraction, Object startValue, Object endValue) {
        int startInt = (Integer) startValue;
        int startA = (startInt >> 24) & 0xff;
        int startR = (startInt >> 16) & 0xff;
        int startG = (startInt >> 8) & 0xff;
        int startB = startInt & 0xff;

        int endInt = (Integer) endValue;
        int endA = (endInt >> 24) & 0xff;
        int endR = (endInt >> 16) & 0xff;
        int endG = (endInt >> 8) & 0xff;
        int endB = endInt & 0xff;

        return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
                (int)((startR + (int)(fraction * (endR - startR))) << 16) |
                (int)((startG + (int)(fraction * (endG - startG))) << 8) |
                (int)((startB + (int)(fraction * (endB - startB))));
    }
}

樣例:this

ValueAnimator backgroundColor = ValueAnimator.ofObject(new ArgbEvaluator(),
                0xffffffff, 0xff000000);
        backgroundColor.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {

            }
            @Override
            public void onAnimationEnd(Animator animation) {

            }
        });
        backgroundColor.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int color = (int) animation.getAnimatedValue();
                mView.setBackgroundColor(color);
            }
        });
        backgroundColor.setInterpolator(new LinearInterpolator());
        backgroundColor.setDuration(500);
        backgroundColor.start();

3. View的animate()方法

咱們也可以直接使用View的API animate()來作動畫,而且還可以幾個動畫同一時候作哦!lua


如下的樣例就實現了一個View的X位移、透明度、縮放的動畫spa

view.animate().translationX(animTranslationXPx)
                .alpha(0.5f)
                .setStartDelay(0)
                .scaleX(0.8f)
                .scaleY(0.8f)
                .setUpdateListener(null)
                .setInterpolator(new AccelerateDecelerateInterpolator())
                .setDuration(1000)
                .withEndAction(new Runnable() {
                    @Override
                    public void run() {

                    }
                })
                .start();

4. ValueAnimator

ValueAnimator就是一個數值產生器,他自己不做用於不論什麼一個對象。但是可以對產生的值進行動畫處理。
爲了實現動畫效果,必須爲ValueAnimator註冊一個監聽器ValueAnimator.AnimatorUpdateListener。該監聽器負責更新對象的屬性值。在實現這個監聽器的時候。可以經過getAnimatedValue()的方法來獲取當前幀的值。code


如下樣例用ValueAnimator來實現了一個縮放和位移動畫:

final Rect fromRect = ......
        final Rect toRect = ......

        final float originScaleX = 1.0f;//(float)fromRect.width() / toRect.width();
        final float originScaleY = 1.0f;//(float)fromRect.height() / toRect.height();

        ValueAnimator trans = ValueAnimator.ofFloat(0, 1);
        trans.setInterpolator(new LinearInterpolator());
        trans.setDuration(600);
        trans.addListener(new AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) { }
            @Override
            public void onAnimationRepeat(Animator animation) { }
            @Override
            public void onAnimationEnd(Animator animation) {

            }
            @Override
            public void onAnimationCancel(Animator animation) {

            }
        });
        trans.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float percent = (Float)animation.getAnimatedValue();

                float toX = (fromRect.left + percent * (toRect.left - fromRect.left));
                float toY = (fromRect.top + percent * (toRect.top - fromRect.top));
                float toR = (fromRect.right + percent * (toRect.right - fromRect.right));
                float toB = (fromRect.bottom + percent * (toRect.bottom - fromRect.bottom));
                float scaleX = (float)(toR - toX) / fromRect.width();
                float scaleY = (float)(toB - toY) / fromRect.height();
                view.setTranslationX(toX-view.getLeft());
                view.setTranslationY(toY-view.getTop());
                view.setScaleX(scaleX*originScaleX);
                view.setScaleY(scaleY*originScaleY);
                float alpha = 0 + percent * 1 / (0.8f - 0);
        ......
            }
        });
        trans.start();

5. ObjectAnimator

ObjectAnimator繼承自ValueAnimator,它會本身主動更新咱們定義的屬性值,來實現動畫的目的。


如下的樣例是用ObjectAnimator來實現X軸位移的動畫:

ObjectAnimator anim = ObjectAnimator.ofFloat(v,View.TRANSLATION_X, newPos);
        anim.setInterpolator(new LinearInterpolator());
        anim.setDuration(500);
        anim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {

            }
        });
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {

            }
        });
        anim.start();

6. AnimatorSet

AnimatorSet用於實現多個動畫的協同做用,AnimatorSet中有一系列的順序控制方法:playTogether、playSequentially、animSet.play().with()、defore()、after()等。

用來實現多個動畫的協同工做方式。
如下的樣例用AnimatorSet實現了縮放和位移動畫:

ObjectAnimator trans = ObjectAnimator.ofFloat(view,View.TRANSLATION_X, newPos);
        ObjectAnimator scalex = ObjectAnimator.ofFloat(view, View.SCALE_X, 1.0f, 0.8f);
        ObjectAnimator scaley = ObjectAnimator.ofFloat(view, View.SCALE_Y, 1.0f, 0.8f);
        AnimatorSet animSet = new AnimatorSet();
        animSet.playTogether(scalex, scaley, trans);
        animSet.setDuration(duration);
        animSet.setInterpolator(new LinearInterpolator());
        animSet.addListener(new AnimatorListener() {

            @Override
            public void onAnimationCancel(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                // do end;
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
            }

            @Override
            public void onAnimationStart(Animator animation) {
            }

        });
        animSet.start();

關於時間的設置問題:
假設AnimatorSet設置了setDuration,那麼不管子動畫有沒有設置時間。都要AnimatorSet的時間爲準,假設AnimatorSet沒有設置。那麼子動畫以各自的時間爲準。當所有動畫完畢後調用onAnimationEnd。

7.使用xml來建立動畫

animation

final Animation ani = AnimationUtils.loadAnimation(this, R.anim.test);
        ani.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
            }
            @Override
            public void onAnimationEnd(Animation animation) {
            }
            @Override
            public void onAnimationRepeat(Animation animation) {
            }
        });
        mView.startAnimation(ani);
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:fromXScale="1.0" android:toXScale="0.2" android:fromYScale="1.0" android:toYScale="1.0" />

固然也可以用如下的方式作。

objectAnimator

Animator ani= AnimatorInflater.loadAnimator(this, R.anim.test);
        ani.setTarget(mView);
        ani.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
            }
        });
        ani.start();

test.xml

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:propertyName="scaleX" android:valueFrom="1.0" android:valueTo="0.2" android:valueType="floatType" >
</objectAnimator>

注意兩個R.anim.test不要用錯,不然會報錯。


經過這個動畫也可以看出通常動畫和屬性動畫的差異:
animation作完動畫後屬性會恢復原樣。也就是說它改變的是View的繪製效果,真正的View的屬性並無改變,animator作完動畫後保持動畫完畢時的屬性不變,說明它把View的屬性改變了。

set

R.anim.test

<set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" android:zAdjustment="top">
    <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:interpolator="@interpolator/test_alpha" android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true" android:duration="336"/>
    <translate android:fromYDelta="15%" android:toYDelta="0" android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" android:interpolator="@interpolator/test_translate" android:duration="336"/>
    <scale android:fromXScale="0.94" android:toXScale="1.0" android:fromYScale="0.94" android:toYScale="1.0" android:interpolator="@interpolator/test_scale" android:duration="336" android:pivotX="50%" android:pivotY="50%"/>
</set>

R.interpolator.test_alpha

<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:controlX1="0.1" android:controlY1="0" android:controlX2="0" android:controlY2="1" />

Java

final Animation ani = AnimationUtils.loadAnimation(mActivity, R.anim.test);
        ani.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
            }
            @Override
            public void onAnimationEnd(Animation animation) {

            }
            @Override
            public void onAnimationRepeat(Animation animation) {
            }
        });     
        imageView.startAnimation(ani);

Animator set

固然也可以用如下的方式實現:
test_animator.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="together" android:shareInterpolator="false" android:zAdjustment="top">
    <objectAnimator  android:propertyName="alpha" android:valueFrom="0.0" android:valueTo="1.0" android:valueType="floatType" android:interpolator="@interpolator/test_alpha" android:duration="336" />
    <objectAnimator  android:propertyName="translationY" android:valueFrom="@dimen/translation_y" android:valueTo="0" android:valueType="floatType" android:interpolator="@interpolator/test_alpha" android:duration="336" />
    <set android:ordering="together">
        <objectAnimator  android:propertyName="scaleX" android:valueFrom="0.94" android:valueTo="1.0" android:valueType="floatType" android:interpolator="@interpolator/test_scale" android:duration="336" />
        <objectAnimator  android:propertyName="scaleY" android:valueFrom="0.94" android:valueTo="1.0" android:valueType="floatType" android:interpolator="@interpolator/test_scale" android:duration="336" />
    </set>
</set>

Java

Animator animator = AnimatorInflater.loadAnimator(mActivity, R.animator.test_animator);
        animator.setTarget(view);
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                end.run();
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                end.run();
            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        animator.start();

8.本身定義ObjectAnimator屬性

一般狀況下咱們使用ObjectAnimator來實現動畫效果,可以用如下的方法:

ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);
anim.setDuration(1000);
anim.start();

因爲在View中已經實現了alpha屬性的動畫,那麼假設在View中沒有實現的屬性咱們怎樣使用ObjectAnimator來作動畫呢?
咱們可以用如下的方法:

ObjectAnimator anim = ObjectAnimator.ofFloat(myTextView, "test", 0f, 1f);
anim.setDuration(1000);
anim.start();

test就表明了View的一個屬性,僅僅需要一個類繼承View並實現

public void setTest(float set){
    //to do something
}

假設用如下這樣僅僅爲該屬性設置一個屬性值,那麼還要實現getter的方法:

ObjectAnimator anim = ObjectAnimator.ofFloat(view, "testt",  1f);
anim.setDuration(1000);
anim.start();

public void setTestt(float set){
    mTestt = set;
}

public float getTestt(){
    return mTestt;
}

固然假設view中沒有該屬性的動畫,那麼還可以用ValueAnimator來實現。僅僅只是要ValueAnimator.AnimatorUpdateListener接口。本身更新對應的屬性值

9.propertyValuesHolder

多動畫效果的另外一種實現方法

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f);
    PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f, 0f, 1f);
    PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f, 0f, 1f);
    ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY, pvhZ)
        .setDuration(1000)
        .start();

10.Keyframe

PropertyValuesHolder的工廠方法裏面,除了整形ofInt()、浮點型ofFloat()、Object類型ofObject()以外,另外一種:ofKeyframe()。


Keyframe類型對象由一個time/value對組成,定義了指定時間點的指定值,即關鍵幀。


每一個keyframe還可以擁有本身的interpolator,控制了前一個關鍵幀到這一個關鍵幀之間的時間動畫行爲。


Keyframe 對象的構造也用是工廠方法:ofInt(), ofFloat(), or ofObject()。


Keyframe對象構造完以後就可以用 ofKeyframe()工廠方法來構造PropertyValuesHolder對象。

Keyframe kf0 = Keyframe.ofFloat(0, 1.0f);
        Keyframe kf1 = Keyframe.ofFloat(0.25f, 0.5f);
        Keyframe kf2 = Keyframe.ofFloat(0.5f, 0f);
        Keyframe kf4 = Keyframe.ofFloat(0.75f, 0.5f);
        Keyframe kf3 = Keyframe.ofFloat(1f, 1.0f);
        PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("alpha", kf0, kf1, kf2, kf4, kf3);
        ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(mView, pvhRotation);
        anim.setDuration(2000);
        anim.start();

上述代碼的意思爲:設置btn對象的width屬性值使其:
開始時 alpha=1.0
動畫開始1/4時 alpha=0.5
動畫開始1/2時 alpha=0
動畫開始3/4時 alpha=0.5
動畫結束時 alpha=1.0
用如下的代碼可以實現相同的效果(上述代碼時間值是線性,變化均勻):

ObjectAnimator oa=ObjectAnimator.ofFloat(mView, "alpha", 1.0f, 0.5f, 0f, 0.5f, 1.0f);
        oa.setDuration(2000);
        oa.start();

11.Interpolator

貝塞爾曲線

一個查看三階貝塞爾曲線效果的站點
http://cubic-bezier.com/#.45,0,.21,1

PathInterpolator

PathInterpolator是android5.0才開始提供的一種時間時間插值器,和LinearInterpolator。AccelerateDecelerateInterpolator同樣用來設置給animator或者animation的,PathInterpolator需要一段起點是(0,0),終點是(1,1)的path路徑。
看它的幾個構造函數:
public PathInterpolator(Path path) :本身定義的Path。但是要保證起點是(0,0)。終點是(1,1)。


public PathInterpolator(float controlX, float controlY):二階的貝塞爾曲線,controlX和controlY是控制點的座標
public PathInterpolator(float controlX1, float controlY1, float controlX2, float controlY2)三階的貝塞爾曲線。(controlX1,controlY1)和(controlX2,controlY2)是兩個控制點的座標。


還可以經過xml方式定義PathInterpolator:

...... ValueAnimator trans = ValueAnimator.ofFloat(0, 1); trans.setInterpolator(enterInterpolator); ......
public Interpolator enterInterpolator;
enterInterpolator= AnimationUtils.loadInterpolator(context,R.interpolator.enter);

enter.xml

<?xml version="1.0" encoding="utf-8"?>

<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:controlX1="0.45" android:controlY1="0" android:controlX2="0.34" android:controlY2="1" />

用android:pathData來描寫敘述一個path

<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:pathData="L0.3,0 C 0.5,0 0.7,1 1, 1" />

二階貝塞爾曲線

<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:controlX1="0.3" android:controlY1="0"/>

加減速引子

<decelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:factor="2.5" />

android:factor 浮點值。加減速速率,默以爲1

相關文章
相關標籤/搜索