動畫的意義:
視覺效果
引導(dǎo)用戶
一、簡介
Android動畫可分為View Animation(視圖動畫)和Property Animation(屬性動畫)。
View Animation包括Tween Animation(補(bǔ)間動畫)和Frame Animation(幀動畫)。
Property Animation包括ValueAnimator和ObjectAnimator。
在Android系統(tǒng)中,視圖動畫繼承至Animation類,而屬性動畫繼承至Animator類。
這里先簡單介紹一下它們的xml使用方式,讓讀者有個大致的了解:
| 動畫類型 | 存放路徑 | 標(biāo)簽 | 獲取方式 | 使用方式 |
|---|---|---|---|---|
| 補(bǔ)間動畫 | res/anim | scale、rotate、translate、alpha、set | AnimationUtils.loadAnimation() | view.startAnimation(anim) |
| 幀動畫 | res/drawable | animation-list | 將drawable作為src或background,然后從View中獲取Drawable,并強(qiáng)轉(zhuǎn)成AnimationDrawable | AnimationDrawable.start() |
| ValueAnimator | res/animator | animator | AnimatorInflater.loadAnimator() | start(),然后在AnimatorUpdateListener回調(diào)中更新View屬性 |
| ObjectAnimator | 同上 | objectAnimator | 同上 | 先setTarget(),再start() |
| AnimatorSet | 同上 | set | 同上 | 同上 |
二、視圖動畫
1、Tween Animation
顧名思義,補(bǔ)間動畫,給出起點(diǎn)、終點(diǎn)、時長、變換方式,系統(tǒng)自動計(jì)算出這個過程中所需要的變換。
Android補(bǔ)間動畫主要有以下5種:
| xml標(biāo)簽 | java類 |
|---|---|
| scale | SacleAnimation |
| alpha | AlphaAnimation |
| rotate | RotateAnimation |
| translate | TranslateAnimation |
| set | AnimationSet |
所有動畫都繼承至Animation,它們都有一些共同的屬性:
| xml屬性 | java方法 | 解釋 |
|---|---|---|
| android:duration | setDuration(long) | 設(shè)置動畫時長 |
| android:fillAfter | setFillAfter | 保持動畫結(jié)束狀態(tài) |
| android:fillBefore | setFillBefore | 動畫結(jié)束時,回到開始狀態(tài) |
| android:repeatCount | setRepeatCount | 設(shè)置重復(fù)次數(shù),[整數(shù)]/[infinite] |
| android:repeatMode | setRepeatMode | 設(shè)置重復(fù)模式,[restart]/[reverse] |
| android:interpolator | setInterpolator(Interpolator) | 設(shè)置插值器 |
其中只有set可以包含多個動畫,并讓其同時生效,如果需要set中,某個動畫延遲運(yùn)行,可以指定startOffset。注意set中repeatCount是無效的,必須對每個動畫單獨(dú)設(shè)置才有作用。
使用方式:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:anim/accelerate_interpolator"
android:shareInterpolator="true"
android:fillAfter="true">
<alpha
android:fromAlpha="0"
android:toAlpha="1"
android:duration="2000" />
<scale
android:fromXScale="0"
android:fromYScale="0"
android:pivotX="50%p"
android:pivotY="50%p"
android:toXScale="1.4"
android:toYScale="1.4"
android:duration="2000" />
<rotate
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="720"
android:duration="2000" />
<translate
android:fromXDelta="0"
android:fromYDelta=0"
android:toXDelta="-80"
android:toYDelta="-80"
android:duration="2000" />
</set>
xml的scale、rotate標(biāo)簽中pivotX和pivotY,表示縮放起始點(diǎn)坐標(biāo),可以是數(shù)值、百分?jǐn)?shù)、百分?jǐn)?shù)p,如50、50%、50%p。
如果是50,則表示在當(dāng)前視圖的左上角,即原點(diǎn)處加上50px,作為縮放起始點(diǎn)的坐標(biāo);
如果是50%,則表示在當(dāng)前控件的左上角加上自己寬度的50%做為縮放起始點(diǎn)的坐標(biāo)。
如果是50%p,則表示在當(dāng)前控件的左上角加上父控件寬度的50%做為縮放起始點(diǎn)的坐標(biāo)。
當(dāng)AnimationSet的shareInterpolator為true時,所有的動畫都會使用定義的interpolator插值器。
private void runTweenAnimation(Context context, View target, int resId) {
Animation anim = AnimationUtils.loadAnimation(context, resId); //java的Animation直接new
anim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) { }
@Override
public void onAnimationEnd(Animation animation) { }
@Override
public void onAnimationRepeat(Animation animation) { }
});
target.startAnimation(anim);
}
2、Frame Animation
也叫幀動畫或者逐幀動畫,由字面意思可以知道,它類似電影一樣,通過逐幀播放,達(dá)到動畫效果。使用方式如下:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot=["true" | "false"]>
<item
android:drawable=""
android:duration="" />
<item
android:drawable=""
android:duration="" />
</animation-list>
android:oneshot:是否是一次性動畫,為true則只會執(zhí)行一次,false則會一直循環(huán) 。
android:drawable:指定此幀動畫所對應(yīng)的圖片資源。
android:duration:此幀動畫持續(xù)的時間,單位為毫秒。
將其設(shè)置為控件的資源或背景
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/anim"
android:src="@drawable/anim" /
最后通過獲取控件的Drawable對象,將其轉(zhuǎn)換成AnimationDrawable并調(diào)用start方法,開啟動畫。
private void runFrameAnimation(ImageView image) {
//AnimationDrawable anim = (AnimationDrawable) image.getBackground();
AnimationDrawable anim = (AnimationDrawable) image.getDrawable();
anim.start();
}
小技巧:當(dāng)知道資源名,但不知道資源 id 時,可通過getResources().getIdentifier(資源名, 資源文件類型, 應(yīng)用包名)獲得。
3、自定義Animation
如果系統(tǒng)提供的5種Animation滿足不了你的需求,如3D效果,則可以自定義Animation。
public class Rrotate3DAnimation extends Animation {
private int mOffsetX;
private int mOffsetY;
private Camera mCamera = new Camera();
private int mRotateY = 30;
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
setDuration(2000);
setFillAfter(true);
setInterpolator(new BounceInterpolator());
mOffsetX = width / 2;
mOffsetY = height / 2;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final Matrix matrix = t.getMatrix();
mCamera.save();
mCamera.rotateY(mRotateY * interpolatedTime);
mCamera.getMatrix(matrix);
mCamera.restore();
matrix.preTranslate(mOffsetX, mOffsetY);
matrix.postTranslate(-mOffsetX, -mOffsetY);
}
}
三、屬性動畫
屬性動畫與視圖動畫的不同之處:
1、視圖動畫繼承至Animation類,而屬性動畫繼承至Animator類。
2、視圖動畫在運(yùn)行過程中,并沒有改變其內(nèi)部屬性(比如觸摸區(qū)域不會隨動畫運(yùn)動而改變)。
屬性動畫可以彌補(bǔ)視圖動畫的不足之處,比如按鈕顏色改變動畫,視圖動畫就難以做到。它可以添加以下監(jiān)聽事件:
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) { }
//執(zhí)行cancel()后,依舊會回調(diào)onAnimationEnd方法
@Override
public void onAnimationEnd(Animator animation) { }
@Override
public void onAnimationCancel(Animator animation) { }
@Override
public void onAnimationRepeat(Animator animation) { }
});
animator.addPauseListener(new Animator.AnimatorPauseListener() {
@Override
public void onAnimationPause(Animator animation) { }
@Override
public void onAnimationResume(Animator animation) { }
});
1、ValueAnimator
ValueAnimator是屬性動畫中常用的一個類,它可以不依賴控件而執(zhí)行,換句話說:它關(guān)注值的改變,而不關(guān)注控件如何去使用這個值。
1、定義
通過資源方式去定義:
定義:res/animator
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:startOffset="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:valueType=["floatType" | "intType" | "pathType" | "colorType"]
android:interpolator=["@android:interpolator/XXX"]/>
獲取:
ValueAnimator anim = (ValueAnimator) AnimationUtils.loadAnimation(context, R.animator.anim);
通過代碼方式去定義:
ValueAnimator anim = ValueAnimator.ofXXX();
anim.setDuration(1000);
anim.setRepeatCount(1);
anim.setRepeatMode(ValueAnimator.REVERSE);
anim.setStartDelay(100);
anim.setInterpolator(new LinearInterpolator());
2、使用
由于ValueAnimator只負(fù)責(zé)對指定值區(qū)間進(jìn)行動畫運(yùn)算,而不會去執(zhí)行具體的動畫,所有我們需要對運(yùn)算過程進(jìn)行監(jiān)聽,然后自己更新控件的屬性,已達(dá)到動畫的效果。
private void runValueAnimator(ValueAnimator anim) {
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 如果是單個屬性動畫
XXX value = (XXX) animation.getAnimatedValue();
// 如果是通過PropertyValuesHolder創(chuàng)建的多個屬性的動畫
XXX value = (XXX) animation.getAnimatedValue("propertyName");
Log.d("TAG", "value = " + value);
}
});
anim.start();
}
2、ObjectAnimator
由于ValueAnimator只能對動畫的數(shù)值進(jìn)行計(jì)算,如果要操作具體的控件,就需要使用監(jiān)聽動畫過程,相比補(bǔ)間動畫煩瑣很多。而ObjectAnimator正是用來彌補(bǔ)這個缺點(diǎn)的。
ObjectAnimator繼承至ValueAnimator,它通過反射來實(shí)現(xiàn)對控件屬性的改變:
通過資源方式去定義:
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="int"
android:propertyName="string"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:startOffset="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:valueType=["floatType" | "intType" | "pathType" | "colorType"]
android:interpolator=["@android:interpolator/XXX"]/>
獲取并使用:
private void runObjectAnimator(Context context, @AnimatorRes int res, View target) {
ObjectAnimator anim = (ObjectAnimator) AnimatorInflater.loadAnimator(context, res);
anim.setTarget(target);
anim.start();
}
通過代碼方式去定義并使用:
ObjectAnimator anim = ObjectAnimator.ofXXX(view, "屬性", ......);
anim.setRepeatCount(1);
anim.setRepeatMode(ValueAnimator.REVERSE);
anim.setStartDelay(100);
anim.setInterpolator(new LinearInterpolator());
animator.start();
ObjectAnimator是通過
反射去調(diào)用屬性的get/set方法,來完成動畫效果。
當(dāng)且僅當(dāng)動畫只有一個過渡值時,系統(tǒng)才會調(diào)用對應(yīng)屬性的get函數(shù)來得到動畫的初始值。
當(dāng)不存在get函數(shù)時,則會取動畫參數(shù)類型的默認(rèn)值作為初始值,如果無默認(rèn)值,將會拋出異常。
3、AnimatorSet
ValueAnimator和ObjectAnimator只能實(shí)現(xiàn)一個動畫,假如我們需要運(yùn)行組合動畫,那該怎么辦?
這就需要用到AnimatorSet了。
通過資源方式去定義:注意:set只能包含objectAnimator標(biāo)簽,不能包含animator標(biāo)簽
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering=["together" | "sequentially"]>
<objectAnimator
......./>
<objectAnimator
......./>
</set>
調(diào)用:
private void runAnimatorSet(Context context, @AnimatorRes int res, View target) {
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(context, res);
anim.setTarget(target);
anim.start();
}
java代碼中創(chuàng)建:
private void runAnimatorSet() {
ObjectAnimator objectAnimator1 = ObjectAnimator.ofInt(textView1,"BackgroundColor", 0xffff00ff, 0xffffff00,0xffff00ff);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(textView1,"translationY",0 , 300, 0);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(textView2, "translationY", 0, 400, 0);
AnimatorSet animatorSet = new AnimatorSet();
//一起執(zhí)行
animatorSet.playTogether(objectAnimator1, objectAnimator2, objectAnimator3);
animatorSet.setDuration(1000);
animatorSet.start();
}
比較兩種創(chuàng)建方式可以發(fā)現(xiàn):通過資源文件創(chuàng)建的集合動畫,適用于一個控件的組合動畫;通過代碼創(chuàng)建的集合動畫,適用于多個控件的組合動畫。
AnimatorSet包含兩個函數(shù):
//讓動畫一起播放
void playTogether(Animator... items)
//動畫依次播放
void playSequentially(Animator... items)
//組合動畫播放延時
void setStartDelay(long startDelay)
注意:這里items可以在各自的組件上執(zhí)行動畫。
playTogether()和playSequentially()函數(shù)在開始動畫時,只是把每個控件的動畫激活,至于每個控件自身的動畫是否延時、是否無限循環(huán),只與控件自身的動畫設(shè)定有關(guān),與playTogether()和playSequentially()函數(shù)無關(guān),它們只負(fù)責(zé)激活動畫。
playSequentially()函數(shù)只有在上一個控件做完動畫以后,才會激活下一個控件的動畫。如果上一個控件的動畫是無限循環(huán)的,那么下一個控件就別指望能做動畫了。
AnimatorSet可以添加監(jiān)聽,但監(jiān)聽不到repeat事件。
AnimatorSet的setDuration(long)、setInterpolator(TimeInterpolator)、setTarget(Object)都會覆蓋單個ObjectAnimator的設(shè)置。
而setStartDelay()函數(shù)不會覆蓋單個動畫的延時,而且僅針對性地延長AnimatorSet的激活時間,單個動畫所設(shè)置的setStartDelay()函數(shù)仍對單個動畫起作用。
AnimatorSet 真正激活延時= AnimatorSet.startDelay +第一個動畫 .startDelay
4、AnimatorSet.Builder
AnimatorSet只能實(shí)現(xiàn)一起動畫和依次動畫,但是如果有特定需求(比如:anim1和anim2同時執(zhí)行,anim3在anim2執(zhí)行完成后執(zhí)行,anim4在anim3執(zhí)行完成后執(zhí)行),那AnimatorSet就難以做的,這時候就需要AnimatorSet.Builder去構(gòu)建動畫。
//表示要執(zhí)行的動畫
public Builder play(Animator anim)
//自身動畫和anim動畫一起執(zhí)行
public Builder with(Animator anim)
//先執(zhí)行完自身動畫,再執(zhí)行anim動畫
public Builder before(Animator anim)
//anim執(zhí)行完后,再執(zhí)行自身動畫
public Builder after(Animator anim)
//延遲delay毫秒之后執(zhí)行動畫
public Builder after(long delay)
5、PropertyValuesHolder與Keyframe
ValueAnimator和ObjectAnimator除了采用ofXXX()靜態(tài)方法產(chǎn)生實(shí)例外,還可以通過ofPropertyValuesHolder()產(chǎn)生實(shí)例。
5.1、PropertyValuesHolder
PropertyValuesHolder保存了動畫過程中所需要操作的屬性和對應(yīng)的值,便于在同一控件上執(zhí)行組合動畫操作(當(dāng)然AnimatorSet也能實(shí)現(xiàn))。
private void runPropertyValuesHolder() {
PropertyValuesHolder rotationHolder = PropertyValuesHolder.ofFloat("rotation", 60f, -60f, 40f, 40f, -20f, 20f, 10f, -10f, 0f);
PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofFloat("alpha", 0.1f, 1f, 0.1f, 1f);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mTextView, rotationHolder, alphaHolder);
animator.setDuration(3000);
animator.start();
}
5.2、Keyframe
Keyframe,也就是關(guān)鍵幀,用來表示某一時刻的控件屬性的值。一個關(guān)鍵幀必須包含兩個元素:時間點(diǎn)和位置。配合PropertyValuesHolder使用,對應(yīng)關(guān)系為:一個ValueAnimator或ObjectAnimator可搭配多個PropertyValuesHolder,一個PropertyValuesHolder可搭配多個Keyframe。
使用Keyframe的流程:
- 生成Keyframe對象
- 利用PropertyValuesHolder.ofKeyframe()函數(shù)生成PropertyValuesHolder對象
- 利用ObjectAnimator.ofPropertyValuesHolder()函數(shù)生成對應(yīng)的Animator。
四、Interpolator和Evaluator
Interpolator(插值器):
Evaluator(估值器):

1、系統(tǒng)自帶插值器:
| 插值器名稱 | 插值器類 | 資源ID | 解釋 |
|---|---|---|---|
| 加減速插值器 | AccelerateDecelerateInterpolator | @android:anim/ accelerate_decelerate_interpolator |
開始加速,結(jié)束減速 |
| 加速插值器 | AccelerateInterpolator | @android:anim/ accelerate_interpolator |
開始速率為0,一直加速 |
| 初始偏移插值器 | AnticipateInterpolator | @android:anim/ anticipate_interpolator |
先向后運(yùn)動一段距離,再向前運(yùn)動 |
| 初始結(jié)束偏移插值器 | AnticipateOvershootInterpolator | @android:anim/ anticipate_overshoot_interpolator |
初始偏移插值器和結(jié)束偏移插值器的合體 |
| 彈跳插值器 | BounceInterpolator | @android:anim/ bounce_interpolator |
類似彈球一樣 先加速到終點(diǎn),再返回一定距離,再去終點(diǎn),依次這樣 |
| 循環(huán)插值器 | CycleInterpolator | @android:anim/ cycle_interpolator |
會往返運(yùn)動,最后回到起點(diǎn) |
| 減速插值器 | DecelerateInterpolator | @android:anim/ decelerate_interpolator |
開始速度最大,然后不斷減速 |
| 線性插值器 | LinearInterpolator | @android:anim/ linear_interpolator |
勻速 |
| 結(jié)束偏移插值器 | OvershootInterpolator | @android:anim/ overshoot_interpolator |
運(yùn)動到結(jié)束位置,繼續(xù)向前,再折返 |
2、自定義插值器
自定義插值器,主要通過實(shí)現(xiàn)TimeInterpolator接口來完成
public interface TimeInterpolator {
/**
* input參數(shù),取值0~1,表示當(dāng)前動畫運(yùn)行進(jìn)度,0表示動畫剛開始,1表示動畫結(jié)束
* 返回值,表示當(dāng)前實(shí)際要顯示的進(jìn)度,可以超出0~1的范圍。小于0表示小于開始位置,大于1表示大于結(jié)束位置
*/
float getInterpolation(float input);
}
3、自定義估值器
由于Interpolator主要即使動畫實(shí)際進(jìn)度,與具體內(nèi)容無關(guān),當(dāng)我們需要計(jì)算別的類型值時,比如Point,就需要自定義估值器了!
自定義估值器,可通過繼承TypeEvaluator實(shí)現(xiàn)。
public class PointEvaluator implements TypeEvaluator<PointF> {
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
float x = startValue.x + (endValue.x - startValue.x) * fraction;
float y = startValue.y + (endValue.y - startValue.y) * fraction;
return new PointF(x, y);
}
}
private void runAnimator() {
ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(), new PointF(0, 0), new PointF(200, 200))
animator.setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF point = (PointF) animation.getAnimatedValue();
Log.d("TAG", "value = " + point);
}
});
animator.setInterpolator(new LinearInterpolator());
animator.start();
}
五、ViewPropertyAnimator
由于構(gòu)建一個屬性動畫流程比較繁瑣,所以谷歌增加了ViewPropertyAnimator,這些動畫依附于控件自身,通過鏈?zhǔn)秸{(diào)用能夠輕松完成動畫的創(chuàng)建和執(zhí)行。
view.animate().rotation(720).setDuration(1000)
animate()方法會返回一個ViewPropertyAnimator對象,注意:ViewPropertyAnimator并非派生自Animator,且構(gòu)建完畢后無需調(diào)用start()方法,動畫會在界面刷新的時候自動啟動。
由于ViewPropertyAnimator并沒有像ObjectAnimator一樣使用反射或JNI技術(shù);而ViewPropertyAnimator會根據(jù)預(yù)設(shè)的每一個動畫幀計(jì)算出對應(yīng)的所有屬性值,并設(shè)置給控件,然后調(diào)用一次invalidate()函數(shù)進(jìn)行重繪,從而解決了在使用ObjectAnimator時每個屬性單獨(dú)計(jì)算、單獨(dú)重繪的問題。使用ViewPropertyAnimator相對于ObjectAnimator和組合動畫,性能有所提升。
并且要實(shí)現(xiàn)一個組合動畫,要么采用AnimatorSet實(shí)現(xiàn),要么使用PropertyValuesHolder,比較繁瑣,而ViewPropertyAnimator非常方便
六、為ViewGroup內(nèi)的組件添加動畫
為ViewGroup內(nèi)的組件添加動畫,常用的有2種方法。
1、android:animateLayoutChanges屬性
給ViewGroup設(shè)置該屬性后,當(dāng)它添加或刪除子控件時,都會有默認(rèn)的動畫效果,但注意:該動畫不能自定義。
2、LayoutTransition
強(qiáng)大且靈活,使用也很方便:
1、創(chuàng)建實(shí)例
LayoutTransition transition = new LayoutTransition();
2、創(chuàng)建動畫并進(jìn)行設(shè)置
ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);
transition.setAnimator(transitionType, animOut);
3、將LayoutTransition設(shè)置到ViewGroup中
viewGroup.setLayoutTransition(transition);
transitionType表示容器狀態(tài)變化類型,目前系統(tǒng)中支持以下5種狀態(tài)變化:
1、APPEARING:容器中出現(xiàn)一個視圖。
2、DISAPPEARING:容器中消失一個視圖。
3、CHANGING:布局改變導(dǎo)致某個視圖隨之改變,例如調(diào)整大小,但不包括添加或者移除視圖。
4、CHANGE_APPEARING:其他視圖的出現(xiàn)導(dǎo)致某個視圖改變。
5、CHANGE_DISAPPEARING:其他視圖的消失導(dǎo)致某個視圖改變。
//初始化
LayoutTransition layoutTransition = new LayoutTransition();
//統(tǒng)一設(shè)置LayoutTransition的動畫時間, ANIMATOR_DURATION定義的常量
layoutTransition.setDuration(LayoutTransition.DISAPPEARING,ANIMATOR_DURATION);
layoutTransition.setDuration(LayoutTransition.APPEARING, ANIMATOR_DURATION);
layoutTransition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, ANIMATOR_DURATION);
layoutTransition.setDuration(LayoutTransition.CHANGE_APPEARING, ANIMATOR_DURATION);
//view 動畫改變時,布局中的每個子view動畫的時間間隔
layoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, 1000);
layoutTransition.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 1000);
//設(shè)置APPEARING行為
ObjectAnimator appearingAnimator = ObjectAnimator.ofFloat(rootView,"scaleY", 0, 1);
appearingAnimator.setDuration(layoutTransition.getDuration(LayoutTransition.APPEARING));
layoutTransition.setAnimator(LayoutTransition.APPEARING,appearingAnimator);
//設(shè)置DISAPPEARING行為
ObjectAnimator disAppearingAnimator = ObjectAnimator.ofFloat(rootView,"scaleY", 1,0);
disAppearingAnimator.setDuration(layoutTransition.getDuration(LayoutTransition.DISAPPEARING));
layoutTransition.setAnimator(LayoutTransition.DISAPPEARING,disAppearingAnimator);
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 0);
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 0);
PropertyValuesHolder pvhRight = PropertyValuesHolder.ofInt("right", 0, 0);
PropertyValuesHolder pvhBottom = PropertyValuesHolder.ofInt("bottom", 0, 0);
//設(shè)置CHANGE_APPEARING行為
PropertyValuesHolder animator = PropertyValuesHolder.ofFloat("rotation", 0, 90, 0);
final ObjectAnimator changeIn = ObjectAnimator.ofPropertyValuesHolder(
this, pvhTop, pvhBottom,pvhLeft, pvhRight, animator).
setDuration(layoutTransition.getDuration(LayoutTransition.CHANGE_APPEARING));
layoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, changeIn);
//設(shè)置CHANGE_DISAPPEARING
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofFloat("scaleX", 1, 1.5f, 1);
final ObjectAnimator changeOut = ObjectAnimator.ofPropertyValuesHolder(
this, pvhTop, pvhBottom,pvhLeft, pvhRight, pvhRotation).
setDuration(layoutTransition.getDuration(LayoutTransition.CHANGE_DISAPPEARING));
layoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changeOut);
rootView.setLayoutTransition(layoutTransition);
通過代碼設(shè)置了4中行為動畫的duration,然后分別為四種行為設(shè)置動畫效果。APPEARING和DISAPPEARING比較簡單,就是定義了一個ObjectAnimator對象,然后通過setAnimator()方法來設(shè)置行為的動畫效果。需要特別注意的是CHANGE_APPEARING和CHANGE_DISAPPEARING行為,需要注意的有這幾點(diǎn):
1、預(yù)先定義了left、top、right和bottom四種動畫
2、CHANGE_APPEARING和CHANGE_DISAPPEARING的自定義動畫效果必須用PropertyAnimator實(shí)現(xiàn)
3、通過ofPropertyValuesHolder方法實(shí)例化ObjectAnimator對象時,必須至少添加left、top、right和bottom中的兩種動畫,建議全都添加上。如果不想left、top、right和bottom屬性發(fā)生改變可以在定義的時候使用0,0或者1,1這種參數(shù)。
4、自定義的CHANGE_APPEARING和CHANGE_DISAPPEARING動畫效果在構(gòu)建時需要指定三個參數(shù)(如:PropertyValuesHolder.ofFloat("scaleX", 1, 1.5f, 1)),且第三個參數(shù)與第一個參數(shù)只能保持一致,特別注意的是絕對不能只設(shè)置2個參數(shù),會使動畫效果無效。這樣的理論基礎(chǔ)是:View執(zhí)行CHANGE_APPEARING和CHANGE_DISAPPEARING動畫效果之后,不能改變其除因?yàn)閂iew添加和移除帶來的相對位置改變之外的其他屬性值。如上圖當(dāng)Button1被移除時,其他View會有一個scaleX的放大效果,但是當(dāng)動畫結(jié)束時其他View不能保持被放大的效果,scaleX必須恢復(fù)到原始屬性值。