Android動畫之ValueAnimator用法和自定義估值器

1 ValueAnimator和估值器簡介

屬性動畫從API11 開始提供,動畫實(shí)現(xiàn)主要依靠ValueAnimator和ObjectAnimator兩個類,類,屬性動畫所在包為android.animation.Animator,和補(bǔ)間動畫有明顯區(qū)別,補(bǔ)間動畫在android.view.animation包目錄下,也說明了屬性動畫不單單作用于view。

ValueAnimator是屬性動畫中重要且最基本的類,ObjectAnimator內(nèi)部也是借助ValueAnimator實(shí)現(xiàn)的。ValueAnimator直接子類有兩個ObjectAnimator和TimeAnimator。

ValueAnimator是數(shù)值從初始值逐漸變化到結(jié)束值,無法直接作用于對象,只能通過設(shè)置動畫監(jiān)聽,獲取動畫過程中的過渡值,然后設(shè)置對象的屬性就可以實(shí)現(xiàn)動畫。默認(rèn)插值器為AccelerateDecelerateInterpolator,插值器只是動畫執(zhí)行的快慢的控制,控制具體動畫過程中獲取的值是通過估值器Evaluator來實(shí)現(xiàn)的。

ValueAnimator可以利用XML文件生成和java代碼生成ValueAnimator類兩種方式實(shí)現(xiàn)動畫。

2 代碼方式生成ValueAnimator

ValueAnimator初始化函數(shù):

  • ValueAnimator.ofInt(int ... values)//處理整形參數(shù)
  • ValueAnimator.ofFloat(float ... values)//處理浮點(diǎn)型
  • ValueAnimator. ofArgb(int... values) //處理顏色
  • ValueAnimator.ofObject(TypeEvaluator evaluator, Object... values)//處理object對象,需要自定義估值器
  • ValueAnimator.ofPropertyValuesHolder(PropertyValuesHolder... values) //處理PropertyValuesHolder

ValueAnimator使用過程:

  • 第一步:利用上面的函數(shù)生成ValueAnimator對象,
  • 第二步:設(shè)置動畫的監(jiān)聽, addUpdateListener(ValueAnimator.AnimatorUpdateListener listener)
  • 第三第:四步利用添加的監(jiān)聽函數(shù)獲取當(dāng)前動畫的值,getAnimatedValue()
  • 第四步:設(shè)置給View,實(shí)現(xiàn)動畫

屬性動畫一般用代碼生成(因?yàn)閷傩灾禑o法寫死在代碼中,一般需要動態(tài)獲?。?,所以本篇主要講解代碼生成方式,XML方式會提一下使用過程。

3 XML方式生成屬性動畫

XML生成屬性動畫三種標(biāo)簽:

  • <animator />: 對應(yīng)ValueAnimator
  • <objectAnimator />: 對應(yīng)ObjectAnimator
  • <set />: 對應(yīng)AnimatorSet
    通用屬性設(shè)置和補(bǔ)間動畫類似,本篇主要講解ValueAnimator,所以標(biāo)簽主要講解<animator/>。
    舉例:
    定義XML文件
<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000" //動畫持續(xù)時長
    android:valueFrom="1" //開始值
    android:valueTo="0"  //結(jié)束值
    android:valueType="floatType" //定義類型為float,相當(dāng)于調(diào)用ValueAnimator.ofFloat()
    android:repeatCount="1" //重復(fù)次數(shù)
 android:repeatMode="reverse" //重復(fù)模式 />

API23 之后還可以利用PropertyValuesHolder和keyframe實(shí)現(xiàn)

<animator xmlns:android="http://schemas.android.com/apk/res/android"
          android:duration="1000"
          android:repeatCount="1"
          android:repeatMode="reverse">
    <propertyValuesHolder>
        <keyframe android:fraction="0" android:value="1"/>
        <keyframe android:fraction=".2" android:value=".4"/>
        <keyframe android:fraction="1" android:value="0"/>
    </propertyValuesHolder>
</animator>

利用AnimatorInflater加載上面定義的xml文件,生成Animator實(shí)例

Animator animator = AnimatorInflater.loadAnimator(context, R.animator.antorXML); 
//如果是ObjectAnimator設(shè)置動畫對象,如果是ValueAnimator則不需要設(shè)置target
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float name = (float) animation.getAnimatedValue();
            }
        });
 animator.setTarget(view); 
 animator.start(); 

xml具體使用步驟總結(jié):

  • 第一步利用XML動畫文件和AnimatorInflater生成ValueAnimator對象
  • 第二步設(shè)置動畫監(jiān)聽
  • 第三步獲取監(jiān)聽的動畫值
  • 第四步設(shè)置給view,執(zhí)行動畫

4 ValueAnimator代碼方式詳解

屬性動畫最好用代碼實(shí)現(xiàn),所以這篇文章也主要側(cè)重代碼實(shí)現(xiàn)。ValueAnimator無法像ObjectAnimator一樣直接作用于對象,只能通過添加監(jiān)聽,獲取動畫過程之,然后手動設(shè)置給對象改變對象的屬性。

4.1 ValueAnimator.ofInt(int ... values)

values可以有多個值,ofInt作用是從初始值(參數(shù)中的第一個)以整數(shù)形式過渡到結(jié)束值,如果參數(shù)有多個,那就是從初始值過渡到第二個參數(shù),然后從第二個參數(shù)過渡到第三個參數(shù),后面以此類推。

mBtn = findViewById(R.id.btn);
imageView = findViewById(R.id.imageview);
valueAnimator = ValueAnimator.ofInt(1, 10);
valueAnimator.setDuration(1000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        int data = (int) animation.getAnimatedValue();
        System.out.println("========getAnimatedValue========="+data);
    }
});

valueAnimator.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationCancel(Animator animation) {
        super.onAnimationCancel(animation);
    }

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

    @Override
    public void onAnimationRepeat(Animator animation) {
        super.onAnimationRepeat(animation);
    }

    @Override
    public void onAnimationStart(Animator animation) {
        super.onAnimationStart(animation);
    }

    @Override
    public void onAnimationPause(Animator animation) {
        super.onAnimationPause(animation);
    }

    @Override
    public void onAnimationResume(Animator animation) {
        super.onAnimationResume(animation);
    }
});
mBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (valueAnimator.isRunning()){
            valueAnimator.cancel();
        }
        valueAnimator.start();
    }
});

輸出結(jié)果:
ofInt函數(shù),獲取到的值都是整形。
========getAnimatedValue=========1
========getAnimatedValue=========1
========getAnimatedValue=========1
========getAnimatedValue=========2
========getAnimatedValue=========4
========getAnimatedValue=========6
========getAnimatedValue=========8
========getAnimatedValue=========9
========getAnimatedValue=========9
========getAnimatedValue=========10

前面我們說了除了插值器,屬性動畫還用到了估值器Evaluator,但是使用ofInt時我們卻沒有設(shè)置估值器,為什么呢?
通過setEvaluator函數(shù)上上面的注釋,可以知道當(dāng)使用ofInt,ofFLoat時系統(tǒng)會自動根據(jù)startValue和endValue給動畫指定估值器。
使用ofInt是使用的估值器是IntEvaluator,使用ofFloat是使用的估值器是FloatEvaluator。

分析IntEvaluator

public class IntEvaluator implements TypeEvaluator<Integer> {
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}

實(shí)現(xiàn)TypeEvaluator,實(shí)現(xiàn)了evaluate函數(shù),evaluate三個參數(shù)的意義:
fraction:動畫運(yùn)行了多久,[0-1]的規(guī)范化數(shù)據(jù),如果設(shè)置duration為1000ms,達(dá)到100ms時,fraction值為0.1,200ms為0.2。
startvalue:開始變化的值,
endValue:變化結(jié)束的值。

TypeEvaluator的evaluate函數(shù)返回值為(int)(startInt + fraction * (endValue - startInt)),
很簡單就是開始值加上動畫運(yùn)行的時間乘以(結(jié)束值減去開始值)。

ofFloat代碼舉例:
ofFloat和onInt用法相同,只是數(shù)值精度不同,不再單獨(dú)講解,舉個例子:

valueAnimator = ValueAnimator.ofFloat(1,0.5f);
valueAnimator.setDuration(1000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float data = (float) animation.getAnimatedValue();
        Matrix matrix = new Matrix();
        matrix.setScale(data,data);
        //ImageView要支持matrix,需要設(shè)置ImageView的ScaleType為matrix
        imageView.setImageMatrix(matrix);
    }
});
image

4.2 ofArgb 顏色漸變

ofArgb是api21提供的新方法,可以幫助我們實(shí)現(xiàn)顏色的漸變:

public static ValueAnimator ofArgb(int... values) {
    ValueAnimator anim = new ValueAnimator();
    anim.setIntValues(values);
    anim.setEvaluator(ArgbEvaluator.getInstance());
    return anim;
}

ofArgb內(nèi)部利用ArgbEvaluator估值器計(jì)算動畫運(yùn)行期間的過渡顏色,所以顏色過渡的算法一定在ArgbEvaluator的evaluate方法中。

valueAnimator = ValueAnimator.ofArgb(Color.RED, Color.GREEN);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        int data = (int) animation.getAnimatedValue();
       imageView.setBackgroundColor(data);
       textView.setBackgroundColor(data);
    }
});
image

4.3 ofObject()

方法:
ofObject(TypeEvaluator evaluator, Object... values)
參數(shù)說明:

  • evaluator:自定義估值器
  • values:開始結(jié)束對象
    ** ofObject處理對象,需要傳入自定義估值器,告訴系統(tǒng)如何計(jì)算動畫運(yùn)行過程中的值。**
public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) {
    ValueAnimator anim = new ValueAnimator();
    anim.setObjectValues(values);
    anim.setEvaluator(evaluator);
    return anim;
}

需要自定義估值器,內(nèi)部會設(shè)置自定義的估值器。

如何自定義估值器

** 上面已經(jīng)分析了IntEvaluator的代碼,下面直接舉例定義一個既能改變顏色,又能改變view高度的估值器。**
首先定義用到的類,存儲屬性值:

public class HeightAndColor  {
    private int color;
    private int height;

    public int getColor() {
        return color;
    }

    public void setColor(int color) {
        this.color = color;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }
}

定義估值器Evaluator
其中顏色漸變利用的RgbaEvaluator的算法。

public class HeightAndColorEvaluator implements TypeEvaluator<HeightAndColor> {
    @Override
    public HeightAndColor evaluate(float fraction, HeightAndColor startValue, HeightAndColor endValue) {
        int startHeight = startValue.getHeight();
        int currHeight = (int) (startHeight + fraction * (endValue.getHeight() - startHeight));
        int currColor = getCurrRGBA(fraction, startValue.getColor(), endValue.getColor());
       HeightAndColor heightAndColor = new HeightAndColor();
       heightAndColor.setColor(currColor);
       heightAndColor.setHeight(currHeight);
        return heightAndColor;
    }

    public int getCurrRGBA(float fraction,int startValue,int endValue){
        int startInt =  startValue;
        float startA = ((startInt >> 24) & 0xff) / 255.0f;
        float startR = ((startInt >> 16) & 0xff) / 255.0f;
        float startG = ((startInt >>  8) & 0xff) / 255.0f;
        float startB = ( startInt        & 0xff) / 255.0f;

        int endInt = endValue;
        float endA = ((endInt >> 24) & 0xff) / 255.0f;
        float endR = ((endInt >> 16) & 0xff) / 255.0f;
        float endG = ((endInt >>  8) & 0xff) / 255.0f;
        float endB = ( endInt        & 0xff) / 255.0f;

        // convert from sRGB to linear
        startR = (float) Math.pow(startR, 2.2);
        startG = (float) Math.pow(startG, 2.2);
        startB = (float) Math.pow(startB, 2.2);

        endR = (float) Math.pow(endR, 2.2);
        endG = (float) Math.pow(endG, 2.2);
        endB = (float) Math.pow(endB, 2.2);

        // compute the interpolated color in linear space
        float a = startA + fraction * (endA - startA);
        float r = startR + fraction * (endR - startR);
        float g = startG + fraction * (endG - startG);
        float b = startB + fraction * (endB - startB);

        // convert back to sRGB in the [0..255] range
        a = a * 255.0f;
        r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;
        g = (float) Math.pow(g, 1.0 / 2.2) * 255.0f;
        b = (float) Math.pow(b, 1.0 / 2.2) * 255.0f;

        return Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);
    }
}

使用定義的估值器:

HeightAndColor heightAndColor1 = new HeightAndColor();
heightAndColor1.setHeight(200);
heightAndColor1.setColor(Color.RED);
HeightAndColor heightAndColor2 = new HeightAndColor();
heightAndColor2.setHeight(400);
heightAndColor2.setColor(Color.GREEN);
valueAnimator = ValueAnimator.ofObject(new HeightAndColorEvaluator(), heightAndColor1, heightAndColor2);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        HeightAndColor data = (HeightAndColor) animation.getAnimatedValue();
        textView.setBackgroundColor(data.getColor());

        ViewGroup.LayoutParams lp = textView.getLayoutParams();
        lp.height=data.getHeight();
        textView.setLayoutParams(lp);
    }
});
image

5 ofPropertyValuesHolder

PropertyValuesHolder類:
這個類持有一個屬性名和對應(yīng)的多個屬性值,動畫運(yùn)行過程中會返回這種類型。ValueAnimator.ofInt(),ValueAnimator.ofFloat()等所有的函數(shù)內(nèi)部都是把值存儲到PropertyValuesHolder中。

ValueAnimator.ofInt函數(shù)

public static ValueAnimator ofInt(int... values) {
    ValueAnimator anim = new ValueAnimator();
    anim.setIntValues(values);
    return anim;
}

//把值存入PropertyValuesHolder中
public void setIntValues(int... values) {
    if (values == null || values.length == 0) {
        return;
    }
    if (mValues == null || mValues.length == 0) {
        setValues(PropertyValuesHolder.ofInt("", values));
    } else {
        PropertyValuesHolder valuesHolder = mValues[0];
        valuesHolder.setIntValues(values);
    }
    // New property/values/target should cause re-initialization prior to starting
    mInitialized = false;
}

所以PropertyValuesHolder是Animator內(nèi)部存儲數(shù)據(jù)用的。

用法實(shí)例:

PropertyValuesHolder propertyValuesHolder1 = PropertyValuesHolder.ofFloat("str1", 1,2,3);
PropertyValuesHolder propertyValuesHolder2 = PropertyValuesHolder.ofFloat("str2", 4,5,6);
valueAnimator = ValueAnimator.ofPropertyValuesHolder(propertyValuesHolder1,propertyValuesHolder2);
valueAnimator.setDuration(1000);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float name = (float) animation.getAnimatedValue("str1");
        float age = (float) animation.getAnimatedValue("str2");
        System.out.println("======1111========"+name+"   "+age);
    }
});

輸出結(jié)果:
======1111========1.0 4.0
======1111========1.0 4.0
======1111========1.034 4.034
======1111========1.266 4.266
======1111========1.5339999 4.534
======1111========1.766 4.766
======1111========2.0 5.0
======1111========2.266 5.266
======1111========2.534 5.534
======1111========2.8 5.8
======1111========3.0 6.0
Animation.getAnimatedValue(“propertyName”)就可以獲取到對應(yīng)的值。

PropertyValuesHolder的ofXX函數(shù)比較多:

ofFloat(Property<?, Float> property, float... values)
ofFloat(String propertyName, float... values)
ofInt(String propertyName, int... values)
ofInt(Property<?, Integer> property, int... values)
ofKeyframe(String propertyName, Keyframe... values)
ofKeyframe(Property property, Keyframe... values)
ofMultiFloat(String propertyName, float[][] values)
ofMultiFloat(String propertyName, TypeConverter<V, float[]> converter, TypeEvaluator<V> evaluator, V... values)
ofMultiFloat(String propertyName, Path path)
ofMultiFloat(String propertyName, TypeConverter<T, float[]> converter, TypeEvaluator<T> evaluator, Keyframe... values)
ofMultiInt(String propertyName, TypeConverter<V, int[]> converter, TypeEvaluator<V> evaluator, V... values)
ofObject(String propertyName, TypeConverter<PointF, ?> converter, Path path)
ofObject(String propertyName, TypeEvaluator evaluator, Object... values)
ofObject(Property<?, V> property, TypeConverter<T, V> converter, TypeEvaluator<T> evaluator, T... values)
。。。。。。

要講解完所有的PropertyValuesHolder函數(shù)篇幅太大,后面會另開文章講解。

Animation動畫概述和執(zhí)行原理
Android動畫之補(bǔ)間動畫TweenAnimation
Android動畫之逐幀動畫FrameAnimation
Android動畫之插值器簡介和系統(tǒng)默認(rèn)插值器
Android動畫之插值器Interpolator自定義
Android動畫之視圖動畫的缺點(diǎn)和屬性動畫的引入
Android動畫之ValueAnimator用法和自定義估值器
Android動畫之ObjectAnimator實(shí)現(xiàn)補(bǔ)間動畫和ObjectAnimator自定義屬性
Android動畫之ObjectAnimator中ofXX函數(shù)全解析-自定義Property,TypeConverter,TypeEvaluator
Android動畫之AnimatorSet聯(lián)合動畫用法
Android動畫之LayoutTransition布局動畫
Android動畫之共享元素動畫
Android動畫之ViewPropertyAnimator(專用于view的屬性動畫)
Android動畫之Activity切換動畫overridePendingTransition實(shí)現(xiàn)和Theme Xml方式實(shí)現(xiàn)
Android動畫之ActivityOptionsCompat概述
Android動畫之場景變換Transition動畫的使用
Android動畫之Transition和TransitionManager使用
Android動畫之圓形揭露動畫Circular Reveal
Android 動畫之 LayoutAnimation 動畫
Android動畫之視圖動畫的缺點(diǎn)和屬性動畫的引入

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容