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);
}
});

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);
}
});

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);
}
});

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)和屬性動畫的引入