在App中合理地使用動畫能夠獲得友好愉悅的用戶體驗,Android中的動畫有View動畫、屬性動畫、幀動畫、布局動畫、轉場動畫等,在5.x以后有又新增了矢量動畫,這些動畫在平常開發(fā)中使用較為普遍,所以有必要做一次完整的總結。
一、View動畫
View動畫定義了漸變Alpha、旋轉Rotate、縮放Scale、平移Translate四種基本動畫,并且通過這四種基本動畫的組合使用,可以實現(xiàn)多種交互效果。
View動畫使用非常簡單,不僅可以通過XML文件來定義動畫,同樣可以通過Java代碼來實現(xiàn)動畫過程。
1.Xml文件定義View動畫
通過xml來定義View動畫涉及到一些公有的屬性(在AndroidStudio上不能提示):
android:duration 動畫持續(xù)時間
android:fillAfter 為true動畫結束時,View將保持動畫結束時的狀態(tài)
android:fillBefore 為true動畫結束時,View將還原到開始開始時的狀態(tài)
android:repeatCount 動畫重復執(zhí)行的次數(shù)
android:repeatMode 動畫重復模式 ,重復播放時restart重頭開始,reverse重復播放時倒敘回放,該屬性需要和android:repeatCount一起使用
android:interpolator 插值器,相當于變速器,改變動畫的不同階段的執(zhí)行速度
這些屬性是從Animation中繼承下來的,在alpha、rotate、scale、translate標簽中都可以直接使用。
利用xml文件定義View動畫需要在工程的res目錄下創(chuàng)建anim文件夾,所有的xml定義的View動畫都要放在anim目錄下。
漸變view_anim_alpha.xml:
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fromAlpha="1.0"
android:toAlpha="0">
</alpha>
旋轉view_anim_rotate.xml:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fillAfter="true"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360">
</rotate>
縮放view_anim_scale.xml:
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0.5"
android:toYScale="0.5">
</scale>
平移view_anim_translate.xml:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="100%"
android:toYDelta="100%">
</translate>
rotate、scale動畫的android:pivotX和android:pivotY屬性、translate動畫的android:toXDelta和android:toYDelta屬性的取值都可以是都可以數(shù)值、百分數(shù)、百分數(shù)p,比如:50、50%、50%p,他們取值的代表的意義各不相同:
50表示以View左上角為原點沿坐標軸正方向(x軸向右,y軸向下)偏移50px的位置;
50%表示以View左上角為原點沿坐標軸正方向(x軸向右,y軸向下)偏移View寬度或高度的50%處的位置;
50%p表示以View左上角為原點沿坐標軸正方向(x軸向右,y軸向下)偏移父控件寬度或高度的50%處的位置(p表示相對于ParentView的位置)。



通過定義xml動畫資源文件,在Activity中調用:
public void clickToAlpha(View view) {
Animation alphaAnim = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.view_anim_alpha);
mTargetView.startAnimation(alphaAnim);
}
public void clickToRotate(View view) {
Animation rotateAnim = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.view_anim_rotate);
mTargetView.startAnimation(rotateAnim);
}
public void clickToScale(View view) {
Animation scaleAnim = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.view_anim_scale);
mTargetView.startAnimation(scaleAnim);
}
public void clickToTranslate(View view) {
Animation translateAnim = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.view_anim_translate);
mTargetView.startAnimation(translateAnim);
}
public void clickToSet(View view) {
Animation setAnim = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.view_anim_set);
mTargetView.startAnimation(setAnim);
}
2.Java代碼實現(xiàn)View動畫
在平常的業(yè)務邏輯中也可以直接用Java代碼來實現(xiàn)Veiw動畫,Android系統(tǒng)給我們提供了AlphaAnimation、RotateAnimation、ScaleAnimation、TranslateAnimation四個動畫類分別來實現(xiàn)View的漸變、旋轉、縮放、平移動畫。
漸變:
public void clickToAlpha(View view) {
AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
alphaAnimation.setDuration(2000);
mTargetView.startAnimation(alphaAnimation);
}
旋轉:
public void clickToRotate(View view) {
RotateAnimation rotateAnimation = new RotateAnimation(
0, 360,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(2000);
mTargetView.startAnimation(rotateAnimation);
}
縮放:
public void clickToScale(View view) {
ScaleAnimation scaleAnimation = new ScaleAnimation(
1, 0.5f,
1, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(2000);
mTargetView.startAnimation(scaleAnimation);
}
平移:
public void clickToTranslate(View view) {
TranslateAnimation translateAnimation = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 1,
Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 1);
translateAnimation.setDuration(2000);
mTargetView.startAnimation(translateAnimation);
}
組合:
public void clickToSet(View view) {
AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
alphaAnimation.setDuration(2000);
RotateAnimation rotateAnimation = new RotateAnimation(
0, 360,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(2000);
ScaleAnimation scaleAnimation = new ScaleAnimation(
1, 0.5f,
1, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(2000);
TranslateAnimation translateAnimation = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 1,
Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 1);
translateAnimation.setDuration(2000);
AnimationSet animationSet = new AnimationSet(true);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(rotateAnimation);
animationSet.addAnimation(scaleAnimation);
animationSet.addAnimation(translateAnimation);
mTargetView.startAnimation(animationSet);
}

View動畫可以設置一個動畫執(zhí)行的監(jiān)聽器:
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// 動畫開始
}
@Override
public void onAnimationEnd(Animation animation) {
// 動畫結束
}
@Override
public void onAnimationRepeat(Animation animation) {
//動畫重復
}
});
通過設置監(jiān)聽器可以在動畫執(zhí)行的開始、結束、重復時做一些其他的業(yè)務邏輯。
二、屬性動畫
所謂屬性動畫,就是改變對象Object的屬性來實現(xiàn)動畫過程。屬性動畫是對View的動畫的擴展,通過它可以實現(xiàn)更多漂亮的動畫效果。同時屬性動畫的作用對象不僅僅是View,任何對象都可以。
屬性動畫的作用效果就是:在一個指定的時間段內將對象的一個屬性的屬性值動態(tài)地變化到另一個屬性值。
1.ObjectAnimator
ObjectAnimator是最常用的屬性動畫執(zhí)行類。
private void startJavaPropertyAnimator() {
ObjectAnimator
.ofFloat(mImageView, "rotationY", 0f, 360f)
.setDuration(2000)
.start();
}
上面的代碼就是通過ObjectAnimator在2000ms內將mImageView的rotationY屬性的屬性值從0f變化的360f。

ObjectAnimtor可以用ofInt、ofFloat、ofObject等靜態(tài)方法,傳入動畫作用的目標Object、屬性字段、屬性開始值、屬性中間值、屬性結束值等參數(shù)來構造動畫對象。在動畫更新的過程中,通過不斷去調用對象屬性的
setter方法改變屬性值,不斷重繪實現(xiàn)動畫過程。如果沒有給定動畫開始屬性值,那么系統(tǒng)會通過反射去獲取Object對象的初始值作為動畫的開始值。屬性動畫也同樣可以通過xml文件來定義,同樣在工程的res目錄下創(chuàng)建animator文件夾,xml文件定義的
objectAnimator動畫要放在該文件夾下。
property_animator.xml:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:propertyName="rotationY"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType">
</objectAnimator>
Java代碼調用:
private void startXmlPropertyAnimator() {
Animator animator = AnimatorInflater.loadAnimator(getApplicationContext(),
R.animator.property_animator);
animator.setTarget(mImageView);
animator.start();
}
最終效果如上圖。
屬性動畫也同樣可以組合使用,通過AnimatorSet類和xml文件的set標簽都可以同時改變對象的多個屬性,實現(xiàn)更加豐富的動畫效果。
通過AnimatorSet創(chuàng)建動畫集:
private void startJavaPropertyAnimatorSet() {
Animator scaleXAnimator = ObjectAnimator.ofFloat(mImageView, "scaleX", 1, 0.5f);
scaleXAnimator.setDuration(2000);
Animator scaleYAnimator = ObjectAnimator.ofFloat(mImageView, "scaleY", 1, 0.5f);
scaleYAnimator.setDuration(2000);
Animator rotationXAnimator = ObjectAnimator.ofFloat(mImageView, "rotationX", 0, 360);
rotationXAnimator.setDuration(2000);
Animator rotationYAnimator = ObjectAnimator.ofFloat(mImageView, "rotationY", 0, 360);
rotationYAnimator.setDuration(2000);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(scaleXAnimator)
.with(scaleYAnimator)
.before(rotationXAnimator)
.after(rotationYAnimator);
animatorSet.start();
}
AnimatorSet通過before、with、after三個方法可以組合多個屬性動畫,with表示與給定動畫同時執(zhí)行,before在給定動畫執(zhí)行之前執(zhí)行,after表示在給定動畫執(zhí)行之后執(zhí)行。

通過xml文件定義屬性動畫集:
property_animator_set.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="2000"
android:propertyName="scaleX"
android:valueFrom="1"
android:valueTo="0.5"
android:valueType="floatType"/>
<objectAnimator
android:duration="2000"
android:propertyName="scaleY"
android:valueFrom="1"
android:valueTo="0.5"
android:valueType="floatType"/>
<objectAnimator
android:duration="2000"
android:propertyName="alpha"
android:valueFrom="1"
android:valueTo="0.5"
android:valueType="floatType"/>
</set>
在Java代碼中調用屬性動畫集:
private void startxmlPropertyAnimatorSet() {
Animator animator = AnimatorInflater.loadAnimator(getApplicationContext(),
R.animator.property_animator_set);
animator.setTarget(mImageView);
animator.start();
}

同樣,屬性動畫也可以添加動畫執(zhí)行監(jiān)聽器:
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
// 動畫開始
}
@Override
public void onAnimationEnd(Animator animation) {
// 動畫結束
}
@Override
public void onAnimationCancel(Animator animation) {
// 動畫取消
}
@Override
public void onAnimationRepeat(Animator animation) {
// 動畫重復
}
});
在監(jiān)聽到屬性動畫開始、結束、取消、重復時可以去做一些其他的邏輯業(yè)務。
2.ValueAnimator
ValueAnimator是ObjectAnimator的父類,它繼承自Animator。ValueAnimaotor同樣提供了ofInt、ofFloat、ofObject等靜態(tài)方法,傳入的參數(shù)是動畫過程的開始值、中間值、結束值來構造動畫對象??梢詫?code>ValueAnimator看著一個值變化器,即在給定的時間內將一個目標值從給定的開始值變化到給定的結束值。在使用ValueAnimator時通常需要添加一個動畫更新的監(jiān)聽器,在監(jiān)聽器中能夠獲取到執(zhí)行過程中的每一個動畫值。
private void startValueAnimator() {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(300);
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 動畫更新過程中的動畫值,可以根據(jù)動畫值的變化來關聯(lián)對象的屬性,實現(xiàn)屬性動畫
float value = (float) animation.getAnimatedValue();
Log.d("ValueAnimator", "動畫值:" + value);
}
});
}
在300ms內將數(shù)值0變化到1的動畫值的變化log:
02-25 23:16:57.586 D/ValueAnimator: 動畫值:0.0
02-25 23:16:57.596 D/ValueAnimator: 動畫值:0.007902175
02-25 23:16:57.616 D/ValueAnimator: 動畫值:0.029559612
02-25 23:16:57.636 D/ValueAnimator: 動畫值:0.066987276
02-25 23:16:57.646 D/ValueAnimator: 動畫值:0.118102014
02-25 23:16:57.666 D/ValueAnimator: 動畫值:0.18128797
02-25 23:16:57.686 D/ValueAnimator: 動畫值:0.2545482
02-25 23:16:57.706 D/ValueAnimator: 動畫值:0.33063102
02-25 23:16:57.716 D/ValueAnimator: 動畫值:0.4166157
02-25 23:16:57.736 D/ValueAnimator: 動畫值:0.5052359
02-25 23:16:57.746 D/ValueAnimator: 動畫值:0.5936906
02-25 23:16:57.766 D/ValueAnimator: 動畫值:0.67918396
02-25 23:16:57.786 D/ValueAnimator: 動畫值:0.7545208
02-25 23:16:57.796 D/ValueAnimator: 動畫值:0.82671034
02-25 23:16:57.826 D/ValueAnimator: 動畫值:0.88857293
02-25 23:16:57.836 D/ValueAnimator: 動畫值:0.93815327
02-25 23:16:57.856 D/ValueAnimator: 動畫值:0.9721882
02-25 23:16:57.876 D/ValueAnimator: 動畫值:0.99384415
02-25 23:16:57.886 D/ValueAnimator: 動畫值:1.0
ValueAnimator的使用一般會結合更新監(jiān)聽器AnimatorUpdateListener,大多數(shù)時候是在自定義控件時使用。
下面是用ValueAnimator自定義控件實現(xiàn)動畫打開關閉效果。
expanded_veiw.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:divider="@drawable/divider"
android:orientation="vertical"
android:showDividers="middle">
<LinearLayout
android:id="@+id/ll_expanded_question"
android:layout_width="match_parent"
android:layout_height="48dp"
android:gravity="center_vertical">
<TextView
android:id="@+id/tv_expanded_question"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:padding="8dp"
android:text="如何把一本很難的書看懂?"
android:textColor="#999999"
android:textSize="16sp"/>
<ImageView
android:id="@+id/iv_expanded_indicator"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginRight="16dp"
android:src="@drawable/img_up"/>
</LinearLayout>
<TextView
android:id="@+id/tv_expanded_answer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="多讀幾遍。真的特別有用。至少看三遍。從開頭看,看到中間,重頭再來,再看得多一點,在從新開始,建議看到快結束時再從新開始。"
android:textColor="#999999"
android:textSize="16sp"/>
</LinearLayout>
public class ExpandedView extends FrameLayout {
private TextView mTvAnswer;
private boolean isClosed;
private ImageView mIvIndicator;
public ExpandedView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
View view = LayoutInflater.from(context).inflate(R.layout.expanded_view, this, true);
LinearLayout llQuestion = (LinearLayout) view.findViewById(R.id.ll_expanded_question);
llQuestion.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
anim();
}
});
mTvAnswer = (TextView) view.findViewById(R.id.tv_expanded_answer);
mIvIndicator = (ImageView) view.findViewById(R.id.iv_expanded_indicator);
}
private void anim() {
// 指示器旋轉
ValueAnimator valueAnimator1 = isClosed
? ValueAnimator.ofFloat(180, 0)
: ValueAnimator.ofFloat(0, 180);
valueAnimator1.setDuration(500);
valueAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
mIvIndicator.setRotation(value);
}
});
valueAnimator1.start();
// 打開開關閉操作
final int answerHeight = mTvAnswer.getMeasuredHeight();
ValueAnimator valueAnimator2 = isClosed
? ValueAnimator.ofInt(-answerHeight, 0)
: ValueAnimator.ofInt(0, -answerHeight);
valueAnimator2.setDuration(500);
final MarginLayoutParams params = (MarginLayoutParams) mTvAnswer.getLayoutParams();
valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
params.bottomMargin = value;
mTvAnswer.setLayoutParams(params);
}
});
valueAnimator2.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
isClosed = !isClosed;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
valueAnimator2.start();
}
}

3.TypeEvaluator
ObjectAnimator和ValueAnimator都有ofObject方法,傳入的都有一個TypeEvaluator類型的參數(shù)。TypeEvaluator是一個接口,里面也只有一個抽象方法:
public T evaluate(float fraction, T startValue, T endValue);
再看ofInt方法中沒有傳入該參數(shù),但實際上調用ofInt方法時,系統(tǒng)已經(jīng)有實現(xiàn)了TypeEvaluator接口的IntEvaluator,它的源碼也非常簡單:
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
fraction范圍為0到1,表示動畫執(zhí)行過程中已完成程度。
泛型T即為動畫執(zhí)行的屬性類型。
所以我們要用屬性動畫來執(zhí)行復雜對象的動畫過程,就需要自定義TypeEvaluator,實現(xiàn)動畫邏輯。
先來定義一個對象
public class Circle {
private int raduis; // 半徑
private int color; // 顏色
private int elevation; // 高度
public Circle(int raduis, int color, int elevation) {
this.raduis = raduis;
this.color = color;
this.elevation = elevation;
}
public int getRaduis() {
return raduis;
}
public void setRaduis(int raduis) {
this.raduis = raduis;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public int getElevation() {
return elevation;
}
public void setElevation(int elevation) {
this.elevation = elevation;
}
}
CircleEvaluator,實現(xiàn)TypeEvaluator接口:
public class CircleEvaluator implements TypeEvaluator<Circle> {
@Override
public Circle evaluate(float fraction, Circle startValue, Circle endValue) {
int startRaduis = startValue.getRaduis();
int endRaduis = endValue.getRaduis();
int raduis = (int) (startRaduis + fraction * (endRaduis - startRaduis));
int startColor = startValue.getColor();
int endColor = endValue.getColor();
int startColorRed = Color.red(startColor);
int startColorGreen = Color.green(startColor);
int startColorBlue = Color.blue(startColor);
int endColorRed = Color.red(endColor);
int endColorGreen = Color.green(endColor);
int endColorBlue = Color.blue(endColor);
int colorRed = (int) (startColorRed + fraction * (endColorRed - startColorRed));
int colorGreen = (int) (startColorGreen + fraction * (endColorGreen - startColorGreen));
int colorBlue = (int) (startColorBlue + fraction * (endColorBlue - startColorBlue));
int color = Color.rgb(colorRed, colorGreen, colorBlue);
int startElevation = startValue.getElevation();
int endElevation = endValue.getElevation();
int elevation = (int) (startElevation + fraction * (endElevation - startElevation));
return new Circle(raduis, color, elevation);
}
}
自定義控件CircleView,將Circle作為它的一個屬性:
public class CircleView extends View {
private Circle circle;
private Paint mPaint;
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
circle = new Circle(168, Color.RED, 0);
mPaint = new Paint();
mPaint.setAntiAlias(true);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
setElevation(circle.getElevation());
mPaint.setColor(circle.getColor());
canvas.drawCircle(getMeasuredHeight() / 2, getMeasuredHeight() / 2, circle.getRaduis(), mPaint);
}
public void setCircle(Circle circle) {
this.circle = circle;
postInvalidate();
}
public Circle getCircle() {
return circle;
}
}
ObjectAnimator使用:
private void start1() {
Circle startCircle = new Circle(168, Color.RED, 0);
Circle middleCircle = new Circle(300, Color.GREEN, 15);
Circle endCircle = new Circle(450, Color.BLUE, 30);
ObjectAnimator.ofObject(mCircleView, "circle", new CircleEvaluator(), startCircle, middleCircle, endCircle)
.setDuration(5000)
.start();
}
ValueAnimator使用:
private void start2() {
Circle startCircle = new Circle(168, Color.RED, 0);
Circle middleCircle = new Circle(300, Color.GREEN, 15);
Circle endCircle = new Circle(450, Color.BLUE, 30);
ValueAnimator valueAnimator = ValueAnimator.ofObject(new CircleEvaluator(), startCircle, middleCircle, endCircle);
valueAnimator.setDuration(5000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Circle circle = (Circle) animation.getAnimatedValue();
mCircleView.setCircle(circle);
}
});
valueAnimator.start();
}

需要注意的是,系統(tǒng)調用獲取控件setter、getter方法是通過反射獲取的,屬性的名稱必須和getter、setter方法名稱后面的字符串一致,比如上面的getter、setter方法分別為
getCircle、setCircle,那么屬性名字就必須為circle。
三、幀動畫
幀動畫需要開發(fā)者制定好動畫每一幀,系統(tǒng)一幀一幀的播放圖片。
private void start1() {
AnimationDrawable ad = new AnimationDrawable();
for (int i = 0; i < 7; i++) {
Drawable drawable = getResources().getDrawable(getResources().getIdentifier("ic_fingerprint_" + i, "drawable", getPackageName()));
ad.addFrame(drawable, 100);
}
ad.setOneShot(false);
mImageView.setImageDrawable(ad);
ad.start();
}
幀動畫同樣也可以在xml文件中配置,直接在工程drawable目錄新建animation-list標簽:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/ic_fingerprint_0" android:duration="100"/>
<item android:drawable="@drawable/ic_fingerprint_1" android:duration="100"/>
<item android:drawable="@drawable/ic_fingerprint_2" android:duration="100"/>
<item android:drawable="@drawable/ic_fingerprint_3" android:duration="100"/>
<item android:drawable="@drawable/ic_fingerprint_4" android:duration="100"/>
<item android:drawable="@drawable/ic_fingerprint_5" android:duration="100"/>
<item android:drawable="@drawable/ic_fingerprint_6" android:duration="100"/>
</animation-list>
private void start2() {
mImageView.setImageResource(R.drawable.frame_anim);
AnimationDrawable animationDrawable = (AnimationDrawable) mImageView.getDrawable();
animationDrawable.start();
}
其中android:onshot屬性和setOneShot方法表示是否只執(zhí)行一次。
AnimationDrawable實際是上是一個Drawable動畫,動畫執(zhí)行的過程總會給你不斷重繪Drawable的每一幀圖像,實現(xiàn)動態(tài)播放效果。
