Android動畫之Animator

Animator動畫可以用xml文件描述和java程序實現。先上一張Animator的官方結構圖

xml實現,新建描述文件res/animator/animator_set1.xml,注意文件放在animator目錄下面。

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="sequentially">

    <objectAnimator
        android:duration="2000"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:propertyName="alpha"
        android:repeatCount="1"
        android:repeatMode="restart"
        android:valueFrom="0"
        android:valueTo="1"
        android:valueType="floatType" />

    <objectAnimator
        android:duration="3000"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:propertyName="scaleX"
        android:valueFrom="0.5"
        android:valueTo="1"
        android:valueType="floatType" />
</set>

屬性解釋:
ordering:有兩個值sequentially和together,前者表示順序播放後者是同時播

duration:動畫播放時長
interpolator:值插器,簡單來說就是控制動畫播放速率的(可以自行查找下)
propertyName:此動畫要作用的View的屬性名稱,一般有getter和setter方法的的屬性都可以使用
repeatCount:動畫重複次數,注意第一次播放不算是重複,所以如果想動畫播放兩次,值爲1就行
repeatMode:重複的模式,兩個值restart和reverse,reverse是指按原動畫倒着來一次,restart自然就是重新播一遍動畫
valueFrom:propertyName屬性的起始值,valueTo就是結束值,valueType屬性值的數值類型

程序中使用:

AnimatorSet animatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.animator_set1);
        animatorSet.setTarget(imageView);
        animatorSet.start();

用java當然也可以達到上面效果,AnimatorSet提供了幾個方法playSequentially()、playTogether()都可以接收ObjecAnimator的Array或者List實現Animator的順序或者同時播放

ObjectAnimator animatorA = ObjectAnimator.ofFloat(imageView, "alpha", 0, 1);
        animatorA.setDuration(2000);
        ObjectAnimator animatorB = ObjectAnimator.ofFloat(imageView, "scaleX", 0.5f, 1.0f);
        animatorB.setDuration(3000);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playSequentially(animatorA, animatorB);
        animatorSet.start();
或者
ObjectAnimator animatorA = ObjectAnimator.ofFloat(imageView, "alpha", 0, 1);
        animatorA.setDuration(2000);
        ObjectAnimator animatorB = ObjectAnimator.ofFloat(imageView, "scaleX", 0.5f, 1.0f);
        animatorB.setDuration(3000);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(animatorA).before(animatorB);
        animatorSet.start();
這樣animatorA播完以後播animatorB,這時候如果有需要和animatorA同時播放的的animatorC,則可以這樣animatorSet.play(animatorA).with(animatorA).before(animatorB),with表示和他前面離with最近的動作一起執行,此時就是animatorA。其實看源碼就知道playTogether的內部是實現就是依靠多次with調用來做的。

另一種稍微複雜一點的描述:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="sequentially">

    <objectAnimator
        android:duration="2000"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:propertyName="alpha"
        android:valueFrom="0"
        android:valueTo="1"
        android:valueType="floatType" />

    <objectAnimator
        android:duration="5000"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator">

        <propertyValuesHolder
            android:propertyName="scaleX"
            android:valueFrom="0.5"
            android:valueTo="1.0"
            android:valueType="floatType" />
        <propertyValuesHolder android:propertyName="x">
            <keyframe
                android:fraction="0.3"
                android:value="600" />
            <keyframe
                android:fraction="1"
                android:value="350" />
        </propertyValuesHolder>
        <propertyValuesHolder android:propertyName="y">
            <keyframe
                android:fraction="0.3"
                android:value="200" />
            <keyframe
                android:fraction="1"
                android:value="300" />
        </propertyValuesHolder>
    </objectAnimator>


</set>


用keyframe完成一個運行軌跡,使用這種方法的時候keyframe的上層標籤objectAnimator不要再描述某些屬性,如android:propertyName="scaleX",不然keyframe將失效。
keyframe的其他屬性沒什麼特別,說下fraction屬性,其取值0<= fraction <=1,動畫時間是fraction的作用對象,0表示起始時間1表示結束時間,中間小數是動畫時間的百分比。運行過程中也可以用interpolator設置速率。同上簡單的java引入就可以使用

用java實現:

ObjectAnimator animatorA = ObjectAnimator.ofFloat(imageView, "alpha", 0, 1);
        animatorA.setDuration(2000);

        PropertyValuesHolder propertyValuesHolder0 = PropertyValuesHolder.ofFloat("scaleX", 0.5f, 1.0f);
        Keyframe keyframe1 = Keyframe.ofFloat(0.3f, 600);
        Keyframe keyframe2 = Keyframe.ofFloat(1f, 350);
        PropertyValuesHolder propertyValuesHolder1 = PropertyValuesHolder.ofKeyframe("x", keyframe1, keyframe2);
        Keyframe keyframe3 = Keyframe.ofFloat(0.3f, 200);
        Keyframe keyframe4 = Keyframe.ofFloat(1f, 300);
        PropertyValuesHolder propertyValuesHolder2 = PropertyValuesHolder.ofKeyframe("y", keyframe3, keyframe4);
        ObjectAnimator animatorB = ObjectAnimator.ofPropertyValuesHolder(imageView, propertyValuesHolder0, propertyValuesHolder1, propertyValuesHolder2);
        animatorB.setDuration(5000);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(animatorA).before(animatorB);
        animatorSet.start();
ObjectAnimator和ProperyValuesHolder都有ofFloat和ofInt不同的是ObjectAnimator比PropertyValuesHolder都多了一個作用對象也就是參數中的target。注意PropertyValuesHolder中只有一個Keyframe會出錯的至少有兩個才行。從以上這些例子中不難發現ObjectAnimator中的PropertyValuesHolder都是同時執行的動畫。

使用ofObject做動畫的時候要指明Evaluator,否則系統不知道這個Object是什麼該怎麼去計算,如PropertryValuesHolder的ofObject函數也能獲得PropertryValuesHolder的實例,使用的時候要指明Evaluator。

        TypeEvaluator<Float> evaluator = new TypeEvaluator<Float>() {
            float startInt;
            @Override
            public Float evaluate(float fraction, Float startValue, Float endValue) {
                startInt  = startValue;
		// fraction是當前運動時間佔總動畫時間的比值
                return startInt + fraction * (endValue - startValue);
            }
        };

        ObjectAnimator animatorA = ObjectAnimator.ofFloat(imageView, "alpha", 0, 1);
        animatorA.setDuration(2000);
        ObjectAnimator animatorB = ObjectAnimator.ofFloat(imageView, "scaleX", 0.5f, 1.0f);
        animatorB.setDuration(3000);
        PropertyValuesHolder propertyValuesHolder0 = PropertyValuesHolder.ofObject("y", evaluator, imgY, 300f);
        ValueAnimator valueAnimator0 = ObjectAnimator.ofPropertyValuesHolder(imageView, propertyValuesHolder0);
        valueAnimator0.setDuration(3000);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(animatorA).with(animatorB).before(valueAnimator0);
        animatorSet.start();

代碼中關於ValueAnimator的部分也可以用以下代替達到上面同樣的效果:

        ValueAnimator valueAnimator0 = new ValueAnimator();
        valueAnimator0.setTarget(imageView);
        valueAnimator0.setObjectValues(imgY, 300f);
        valueAnimator0.setEvaluator(evaluator);
        valueAnimator0.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float y = (float) animation.getAnimatedValue();
                imageView.setY(y);
            }
        });

AnimatorUpdateListener是對動畫的值更新進行監聽,我們能在回調函數中獲取到某屬性當前的值,單一屬性值的改變不用指定屬性名稱如上。

還有一個簡單的動畫類,ViewPropertyAnimator,使用很簡單,簡單的動畫可以用它
        ViewPropertyAnimator propertyAnimator = imageView.animate();
        propertyAnimator.translationXBy(100)
                .setDuration(1000)
                .start();


Animator的監聽器添加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) {}
        }
// 對AnimatorListener的空實現,並且多出兩個    
 new AnimatorListenerAdapter() {

            @Override
            public void onAnimationCancel(Animator animation) {}
            @Override
            public void onAnimationEnd(Animator animation) {}
            @Override
            public void onAnimationRepeat(Animator animation) {}
            @Override
            public void onAnimationStart(Animator animation) {}
            @Override
            public void onAnimationPause(Animator animation) {}
            @Override
            public void onAnimationResume(Animator animation) {}

        }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章