1. 程式人生 > >Android 屬性動畫 常用方法 與 插值器 Interpolator

Android 屬性動畫 常用方法 與 插值器 Interpolator

轉載於。加了點自己的修改

ViewPropertyAnimator

使用方法

view.animate().translationX(500);  

這裡寫圖片描述

具體可以跟的方法以及方法所對應的 View 中的實際操作的方法如下圖所示:

這裡寫圖片描述

從圖中可以看到, View 的每個方法都對應了 ViewPropertyAnimator 的兩個方法,其中一個是帶有 -By 字尾的,例如,View.setTranslationX() 對應了 ViewPropertyAnimator.translationX() 和 ViewPropertyAnimator.translationXBy() 這兩個方法。其中帶有 -By() 字尾的是增量版本的方法,例如,translationX(100) 表示用動畫把 View 的 translationX 值漸變為 100,而 translationXBy(100) 則表示用動畫把 View 的 translationX 值漸變地增加 100。l

這些方法的效果都簡單易懂,而且視訊裡也有簡單的演示,所以就不放示例圖了。如果你想看,可以去下面的練習專案。(最好順便也練一下程式碼)

ObjectAnimator

使用方式:

如果是自定義控制元件,需要新增 setter / getter 方法;
用 ObjectAnimator.ofXXX() 建立 ObjectAnimator 物件;
用 start() 方法執行動畫。

public class SportsView extends View {float progress = 0;

    ......

    // 建立 getter 方法
    public
float getProgress() { return progress; } // 建立 setter 方法 public void setProgress(float progress) { this.progress = progress; invalidate(); } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); ...... canvas.drawArc(arcRectF, 135
, progress * 2.7f, false, paint); ...... } } ...... // 建立 ObjectAnimator 物件 ObjectAnimator animator = ObjectAnimator.ofFloat(view, "progress", 0, 65); // 執行動畫 animator.start();

這裡寫圖片描述

常用方法

1. setDuration(int duration) 設定動畫時長

單位是毫秒。

// imageView1: 500 毫秒
imageView1.animate()  
        .translationX(500)
        .setDuration(500);

// imageView2: 2 秒
ObjectAnimator animator = ObjectAnimator.ofFloat(  
        imageView2, "translationX", 500);
animator.setDuration(2000);  
animator.start();  

這裡寫圖片描述

2. setInterpolator(Interpolator interpolator) 設定 Interpolator

Interpolator 其實就是速度設定器。你在引數裡填入不同的 Interpolator ,動畫就會以不同的速度模型來執行。

// imageView1: 線性 Interpolator,勻速
imageView1.animate()  
        .translationX(500)
        .setInterpolator(new LinearInterpolator());

// imageView: 帶施法前搖和回彈的 Interpolator
ObjectAnimator animator = ObjectAnimator.ofFloat(  
        imageView2, "translationX", 500);
animator.setInterpolator(new AnticipateOvershootInterpolator());  
animator.start();  

這裡寫圖片描述

這裡寫圖片描述

簡單介紹一下每一個 Interpolator。

插值器 Interpolator 大全

AccelerateDecelerateInterpolator

先加速再減速。這是預設的 Interpolator,也就是說如果你不設定的話,那麼動畫將會使用這個 Interpolator。

視訊裡已經說過了,這個是一種最符合現實中物體運動的 Interpolator,它的動畫效果看起來就像是物體從速度為 0 開始逐漸加速,然後再逐漸減速直到 0 的運動。它的速度 / 時間曲線以及動畫完成度 / 時間曲線都是一條正弦 / 餘弦曲線(這句話看完就忘掉就行,沒用)。具體的效果如下

這裡寫圖片描述

好像不太看得出來加速減速過程?你就將就著看吧,畢竟 gif 不是視訊,要啥自行車啊。

用途:就像上面說的,它是一種最符合物理世界的模型,所以如果你要做的是最簡單的狀態變化(位移、放縮、旋轉等等),那麼一般不用設定 Interpolator,就用這個預設的最好。

LinearInterpolator

勻速。

勻速就不用解釋了吧?直接上效果:

這裡寫圖片描述

AccelerateInterpolator

持續加速。

在整個動畫過程中,一直在加速,直到動畫結束的一瞬間,直接停止。

這裡寫圖片描述

別看見它加速驟停就覺得這是個神經病模型哦,它很有用的。它主要用在離場效果中,比如某個物體從介面中飛離,就可以用這種效果。它給人的感覺就會是「這貨從零起步,加速飛走了」。到了最後動畫驟停的時候,物體已經飛出使用者視野,看不到了,所以他們是並不會察覺到這個驟停的。

DecelerateInterpolator

持續減速直到 0。

動畫開始的時候是最高速度,然後在動畫過程中逐漸減速,直到動畫結束的時候恰好減速到 0。

這裡寫圖片描述

它的效果和上面這個 AccelerateInterpolator 相反,適用場景也和它相反:它主要用於入場效果,比如某個物體從介面的外部飛入介面後停在某處。它給人的感覺會是「咦飛進來個東西,讓我仔細看看,哦原來是 XXX」。

AnticipateInterpolator

先回拉一下再進行正常動畫軌跡。效果看起來有點像投擲物體或跳躍等動作前的蓄力。

這裡寫圖片描述

如果是圖中這樣的平移動畫,那麼就是位置上的回拉;如果是放大動畫,那麼就是先縮小一下再放大;其他型別的動畫同理。

這個 Interpolator 就有點耍花樣了。沒有通用的適用場景,根據具體需求和設計師的偏好而定。

OvershootInterpolator

動畫會超過目標值一些,然後再彈回來。效果看起來有點像你一屁股坐在沙發上後又被彈起來一點的感覺。

這裡寫圖片描述

和 AnticipateInterpolator 一樣,這是個耍花樣的 Interpolator,沒有通用的適用場景。

AnticipateOvershootInterpolator

上面這兩個的結合版:開始前回拉,最後超過一些然後回彈。

這裡寫圖片描述

依然耍花樣,不多解釋。

BounceInterpolator

在目標值處彈跳。有點像玻璃球掉在地板上的效果。

這裡寫圖片描述

CycleInterpolator

這個也是一個正弦 / 餘弦曲線,不過它和 AccelerateDecelerateInterpolator 的區別是,它可以自定義曲線的週期,所以動畫可以不到終點就結束,也可以到達終點後回彈,回彈的次數由曲線的週期決定,曲線的週期由 CycleInterpolator() 構造方法的引數決定。

引數為 0.5f:

這裡寫圖片描述

引數為 2f:

這裡寫圖片描述

PathInterpolatorCompat

與下面使用類似 PathInterpolator 的相容版

ObjectAnimator translationX = ObjectAnimator.ofFloat(mImageView, "translationX", 500);
Path interpolatorPath = new Path();
// 先以「動畫完成度 : 時間完成度 = 1 : 1」的速度勻速執行 25%
interpolatorPath.lineTo(0.25f, 0.25f);
// 然後瞬間跳躍到 150% 的動畫完成度
interpolatorPath.moveTo(0.25f, 1.5f);
// 再勻速倒車,返回到目標點
interpolatorPath.lineTo(1, 1);

Interpolator interpolator = PathInterpolatorCompat.create(interpolatorPath);
translationX.setInterpolator(interpolator);
translationX.setDuration(2000);
translationX.start();

PathInterpolator 5.0 +

自定義動畫完成度 / 時間完成度曲線。

用這個 Interpolator 你可以定製出任何你想要的速度模型。定製的方式是使用一個 Path 物件來繪製出你要的動畫完成度 / 時間完成度曲線。例如:

Path interpolatorPath = new Path();

...

// 勻速
interpolatorPath.lineTo(1, 1);  

這裡寫圖片描述

這裡寫圖片描述

Path interpolatorPath = new Path();

...

// 先以「動畫完成度 : 時間完成度 = 1 : 1」的速度勻速執行 25%
interpolatorPath.lineTo(0.25f, 0.25f);  
// 然後瞬間跳躍到 150% 的動畫完成度
interpolatorPath.moveTo(0.25f, 1.5f);  
// 再勻速倒車,返回到目標點
interpolatorPath.lineTo(1, 1);  

這裡寫圖片描述

這裡寫圖片描述

你根據需求,繪製出自己需要的 Path,就能定製出你要的速度模型。

不過要注意,這條 Path 描述的其實是一個 y = f(x) (0 ≤ x ≤ 1) (y 為動畫完成度,x 為時間完成度)的曲線,所以同一段時間完成度上不能有兩段不同的動畫完成度(這個好理解吧?因為內容不能出現分身術呀),而且每一個時間完成度的點上都必須要有對應的動畫完成度(因為內容不能在某段時間段內消失呀)。所以,下面這樣的 Path 是非法的,會導致程式 FC:

這裡寫圖片描述

出現重複的動畫完成度,即動畫內容出現「分身」——程式 FC

這裡寫圖片描述

有一段時間完成度沒有對應的動畫完成度,即動畫出現「中斷」——程式 FC

除了上面的這些,Android 5.0 (API 21)引入了三個新的 Interpolator 模型,並把它們加入了 support v4 包中。這三個新的 Interpolator 每個都和之前的某個已有的 Interpolator 規則相似,只有略微的區別。

FastOutLinearInInterpolator

加速運動

這個 Interpolator 的作用你不能看它的名字,一會兒 fast 一會兒 linear 的,完全看不懂。其實它和 AccelerateInterpolator 一樣,都是一個持續加速的運動路線。只不過 FastOutLinearInInterpolator 的曲線公式是用的貝塞爾曲線,而 AccelerateInterpolator 用的是指數曲線。具體來說,它倆最主要的區別是 FastOutLinearInInterpolator 的初始階段加速度比 AccelerateInterpolator 要快一些。

FastOutLinearInInterpolator:

這裡寫圖片描述

這裡寫圖片描述

AccelerateInterpolator:

這裡寫圖片描述

這裡寫圖片描述

能看出它倆的區別嗎?

能看出來就怪了。這倆的速度模型幾乎就是一樣的,不信我把它們的動畫完成度 / 時間完成度曲線放在一起給你看:

這裡寫圖片描述

到了嗎?兩條線幾乎是一致的,只是紅線比綠線更早地到達了較高的斜率,這說明在初始階段,FastOutLinearInInterpolator 的加速度比 AccelerateInterpolator 更高。

那麼這意味著什麼呢?

意味個毛。實際上,這點區別,在實際應用中使用者根本察覺不出來。而且,AccelerateInterpolator 還可以在構造方法中調節變速係數,分分鐘調節到和 FastOutLinearInInterpolator (幾乎)一模一樣。所以你在使用加速模型的時候,這兩個選哪個都一樣,沒區別的。

那麼既然都一樣,我做這麼多對比,講這麼些幹什麼呢?

因為我得讓你瞭解。它倆雖然「用起來沒區別」,但這是基於我對它足夠了解所做出的判斷,可我如果直接甩給你一句「它倆沒區別,想用誰用誰,少廢話別問那麼多」,你心裡肯定會有一大堆疑問,在開發時用到它們的時候也會畏畏縮縮心裡打鼓的,對吧?

FastOutSlowInInterpolator

先加速再減速。

同樣也是先加速再減速的還有前面說過的 AccelerateDecelerateInterpolator,不過它們的效果是明顯不一樣的。FastOutSlowInInterpolator 用的是貝塞爾曲線,AccelerateDecelerateInterpolator 用的是正弦 / 餘弦曲線。具體來講, FastOutSlowInInterpolator 的前期加速度要快得多。

這裡寫圖片描述

這裡寫圖片描述

AccelerateDecelerateInterpolator:

這裡寫圖片描述

這裡寫圖片描述

不論是從動圖還是從曲線都可以看出,這二者比起來,FastOutSlowInInterpolator 的前期加速更猛一些,後期的減速過程的也減得更迅速。用更直觀一點的表達就是,AccelerateDecelerateInterpolator 像是物體的自我移動,而 FastOutSlowInInterpolator 則看起來像有一股強大的外力「推」著它加速,在接近目標值之後又「拽」著它減速。總之,FastOutSlowInterpolator 看起來有一點「著急」的感覺。

二者曲線對比圖:

這裡寫圖片描述

LinearOutSlowInInterpolator

持續減速。

它和 DecelerateInterpolator 比起來,同為減速曲線,主要區別在於 LinearOutSlowInInterpolator 的初始速度更高。對於人眼的實際感覺,區別其實也不大,不過還是能看出來一些的。

LinearOutSlowInInterpolator:

這裡寫圖片描述

這裡寫圖片描述

DecelerateInterpolator:

這裡寫圖片描述

這裡寫圖片描述

二者曲線對比:

這裡寫圖片描述

對於所有 Interpolator 的介紹就到這裡。這些 Interpolator,有的較為常用且有通用的使用場景,有的需要你自己來根據情況而定。把它們瞭解清楚了,對於製作出觀感舒服的動畫很有好處。

設定監聽器

給動畫設定監聽器,可以在關鍵時刻得到反饋,從而及時做出合適的操作,例如在動畫的屬性更新時同步更新其他資料,或者在動畫結束後回收資源等。

設定監聽器的方法, ViewPropertyAnimator 和 ObjectAnimator 略微不一樣: ViewPropertyAnimator 用的是 setListener() 和 setUpdateListener() 方法,可以設定一個監聽器,要移除監聽器時通過 set[Update]Listener(null) 填 null 值來移除;而 ObjectAnimator 則是用 addListener() 和 addUpdateListener() 來新增一個或多個監聽器,移除監聽器則是通過 remove[Update]Listener() 來指定移除物件。

另外,由於 ObjectAnimator 支援使用 pause() 方法暫停,所以它還多了一個 addPauseListener() / removePauseListener() 的支援;而 ViewPropertyAnimator 則獨有 withStartAction() 和 withEndAction() 方法,可以設定一次性的動畫開始或結束的監聽。

ViewPropertyAnimator.setListener() / ObjectAnimator.addListener()

這兩個方法的名稱不一樣,可以設定的監聽器數量也不一樣,但它們的引數型別都是 AnimatorListener,所以本質上其實都是一樣的。 AnimatorListener 共有 4 個回撥方法:

onAnimationStart(Animator animation)

當動畫開始執行時,這個方法被呼叫。

onAnimationEnd(Animator animation)

當動畫結束時,這個方法被呼叫。

onAnimationCancel(Animator animation)

當動畫被通過 cancel() 方法取消時,這個方法被呼叫。

需要說明一下的是,就算動畫被取消,onAnimationEnd() 也會被呼叫。所以當動畫被取消時,如果設定了 AnimatorListener,那麼 onAnimationCancel() 和 onAnimationEnd() 都會被呼叫。onAnimationCancel() 會先於 onAnimationEnd() 被呼叫。

onAnimationRepeat(Animator animation)

當動畫通過 setRepeatMode() / setRepeatCount() 或 repeat() 方法重複執行時,這個方法被呼叫。

由於 ViewPropertyAnimator 不支援重複,所以這個方法對 ViewPropertyAnimator 相當於無效。

ViewPropertyAnimator.setUpdateListener() / ObjectAnimator.addUpdateListener()

和上面 3.1 的兩個方法一樣,這兩個方法雖然名稱和可設定的監聽器數量不一樣,但本質其實都一樣的,它們的引數都是 AnimatorUpdateListener。它只有一個回撥方法:onAnimationUpdate(ValueAnimator animation)。

onAnimationUpdate(ValueAnimator animation)

當動畫的屬性更新時(不嚴謹的說,即每過 10 毫秒,動畫的完成度更新時),這個方法被呼叫。

方法的引數是一個 ValueAnimator,ValueAnimator 是 ObjectAnimator 的父類,也是 ViewPropertyAnimator 的內部實現,所以這個引數其實就是 ViewPropertyAnimator 內部的那個 ValueAnimator,或者對於 ObjectAnimator 來說就是它自己本身。

ValueAnimator 有很多方法可以用,它可以檢視當前的動畫完成度、當前的屬性值等等。不過 ValueAnimator 是下一期才講的內容,所以這期就不多說了。

ObjectAnimator.addPauseListener()

由於 ObjectAnimator.pause() 是下期的內容,所以這個方法在這期就不講了。當然,如果你有興趣的話,現在就瞭解一下也可以。

ViewPropertyAnimator.withStartAction/EndAction()

這兩個方法是 ViewPropertyAnimator 的獨有方法。它們和 set/addListener() 中回撥的 onAnimationStart() / onAnimationEnd() 相比起來的不同主要有兩點:

  1. withStartAction() / withEndAction() 是一次性的,在動畫執行結束後就自動棄掉了,就算之後再重用 ViewPropertyAnimator 來做別的動畫,用它們設定的回撥也不會再被呼叫。而 set/addListener() 所設定的 AnimatorListener 是持續有效的,當動畫重複執行時,回撥總會被呼叫。

  2. withEndAction() 設定的回撥只有在動畫正常結束時才會被呼叫,而在動畫被取消時不會被執行。這點和 AnimatorListener.onAnimationEnd() 的行為是不一致的