一、Android 動畫知識總結(jié)(View動畫)

動畫的意義:
視覺效果
引導(dǎo)用戶

一、簡介

Android動畫可分為View Animation(視圖動畫)和Property Animation(屬性動畫)。
View Animation包括Tween Animation(補(bǔ)間動畫)和Frame Animation(幀動畫)。
Property Animation包括ValueAnimatorObjectAnimator。

在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的流程:

  1. 生成Keyframe對象
  2. 利用PropertyValuesHolder.ofKeyframe()函數(shù)生成PropertyValuesHolder對象
  3. 利用ObjectAnimator.ofPropertyValuesHolder()函數(shù)生成對應(yīng)的Animator。

四、Interpolator和Evaluator

Interpolator(插值器):
Evaluator(估值器):

image.png

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ù)到原始屬性值。


七、DynamicAnimation

最后編輯于
?著作權(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)容

  • 1 背景 不能只分析源碼呀,分析的同時也要整理歸納基礎(chǔ)知識,剛好有人微博私信讓全面說說Android的動畫,所以今...
    未聞椛洺閱讀 2,861評論 0 10
  • 【Android 動畫】 動畫分類補(bǔ)間動畫(Tween動畫)幀動畫(Frame 動畫)屬性動畫(Property ...
    Rtia閱讀 6,446評論 1 38
  • 轉(zhuǎn)載一篇高質(zhì)量博文,原地址請戳這里轉(zhuǎn)載下來方便今后查看。1 背景不能只分析源碼呀,分析的同時也要整理歸納基礎(chǔ)知識,...
    Elder閱讀 2,015評論 0 24
  • Animation Animation類是所有動畫(scale、alpha、translate、rotate)的基...
    四月一號閱讀 2,035評論 0 10
  • 1 背景 不能只分析源碼呀,分析的同時也要整理歸納基礎(chǔ)知識,剛好有人微博私信讓全面說說Android的動畫,所以今...
    lisx_閱讀 1,010評論 0 0

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