這多是第二好的自定義 View 教程之屬性動畫

上期文章鎮樓:
這多是第二好的自定義 View 教程之繪製java

凱哥的文章確實寫的細而好呀,這不,活生生把 面試系列 先放一放,繼續講解咱們的動畫。面試

不是講全部動畫

Android 裏面對動畫能夠進行一些分類,主要分爲兩類:canvas

  • Animation微信

  • Transitionide

因爲 「Transtion」 重點在於切換而不是動畫,因此咱們今天直接忽略。廢話不用多說,那麼咱們就直接講解屬性動畫「Property Animation」吧。性能

如今的項目中的動畫 99% 都是用的屬性動畫,因此咱們不講 View Animation。動畫

ViewPropertyAnimator

這一塊比較簡單,咱們能夠直接引用凱哥這裏的總結圖。(凱哥文章,業界良心,真的很贊。)ui

圖片來自 HenCoder

從圖中能夠看到, View 的每一個方法都對應了 ViewPropertyAnimator 的兩個方法,其中一個是帶有 -By 後綴的,例如,View.setTranslationX() 對應了 ViewPropertyAnimator.translationX()ViewPropertyAnimator.translationXBy() 這兩個方法。其中帶有 -By() 後綴的是增量版本的方法,例如,translationX(100) 表示用動畫把 View 的 translationX 值漸變爲 100,而 translationXBy(100) 則表示用動畫把 View 的 translationX 值 漸變地增長 100。this

其中的 ViewPropertyAnimator 能夠經過 View.animate() 獲得。spa

/**
     * This method returns a ViewPropertyAnimator object, which can be used to animate
     * specific properties on this View.
     *
     * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View.
     */
    public ViewPropertyAnimator animate() {
        if (mAnimator == null) {
            mAnimator = new ViewPropertyAnimator(this);
        }
        return mAnimator;
    }

ObjectAnimator

使用方式:

  • 若是是自定義控件,須要添加 setter / getter 方法;

  • ObjectAnimator.ofXXX() 建立 ObjectAnimator 對象;

  • start() 方法執行動畫。

其中特別須要注意的是:

  • setter() 方法須要調用 invalidate() 對 View 進行重繪。

  • **獲取 ObjectAnimator 採用的是 ObjectAnimator.ofXXX() 方法。

至因而 「ofFloat」仍是「ofInt」仍是別的,這個徹底視你的 View 參數而定,而且第二個參數用 setXXX 的「XXX」字符串。**

  • 上面 ViewPropertyAnimator 方法基本都是通用的。

  • 固然,當你看到 ObjectAnimator.ofObject() 方法的時候,你會心生疑惑,這其實就是爲了對不限定類型的屬性作動畫。

例子也懶得寫了,直接用凱哥的。

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

圖片來自 HenCoder

固然,這些動畫都是能夠自由組合的,支持「鏈式調用」,由於它們返回的都是 ViewPropertyAnimator

好比這樣。

view.animate()  
        .scaleX(1)
        .scaleY(1)
        .alpha(1);

圖片來自 HenCoder

而對於 ObjectAnimator,是不能這麼用的。不過你可使用 PropertyValuesHolder 來同時在一個動畫中改變多個屬性。

PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 1);  
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 1);  
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 1);

ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder1, holder2, holder3)  
animator.start();

從上面的 gif 圖能夠發現,動畫是同步進行的,那要是咱們但願依次執行怎麼辦?好比這樣,先放大再平移。

圖片來自 HenCoder

萬能的 Android 天然難不倒咱們,這樣就有了 AnimatorSet

AnimatorSet 多個動畫配合執行

AnimatorSet.playSequentially(Animator... items) 完美地解決了咱們上面的疑惑。

AnimatorSet animatorSet = new AnimatorSet();  
// 兩個動畫依次執行
animatorSet.playSequentially(animator1, animator2);  
animatorSet.start();

其中 「animator1」和「animator2」分別是放大和平移的動畫。

翻閱官方源碼一看,其實不止 playSequentially() 一個方法,除了順序執行,固然有其餘方法,好比:

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(animator1).before(animator2); // 先執行 1 再執行 2
animatorSet.playTogether(animator2, animator3); // 2 和 3 同時開始
animatorSet.start();

相似的處理方案,還不少不少方式,具體你能夠查看官方源碼。

僅靠這些方法作出來的動畫效果說實話已經很炫了,不過咱們老是不知足,好比咱們設計師想這樣怎麼辦?

圖片來自 HenCoder

圖片中先是將進度填到了 100,再降回了實際的值。這利用上面所提到的知識,好像根本無法實現,這效果有意思,咱們看看怎麼實現。

PropertyValuesHolders.ofKeyframe() 把同一個屬性拆分

除了合併多個屬性和調配多個動畫,你還能夠在 PropertyValuesHolder 的基礎上更進一步,經過設置 Keyframe (關鍵幀),把同一個動畫屬性拆分紅多個階段。好比,要實現上面的效果,你只需:

// 在 0% 處開始
Keyframe keyframe1 = Keyframe.ofFloat(0, 0);  
// 時間通過 50% 的時候,動畫完成度 100%
Keyframe keyframe2 = Keyframe.ofFloat(0.5f, 100);  
// 時間見過 100% 的時候,動畫完成度倒退到 80%,即反彈 20%
Keyframe keyframe3 = Keyframe.ofFloat(1, 80);  
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("progress", keyframe1, keyframe2, keyframe3);

ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder);  
animator.start();

先小結一下,「關於複雜的屬性關係來作動畫」,就這麼三種:

  • 使用 PropertyValuesHolder 來對多個屬性同時作動畫;

  • 使用 AnimatorSet 來同時管理調配多個動畫;

  • PropertyValuesHolder 的進階使用:使用 PropertyValuesHolder.ofKeyframe() 來把一個屬性拆分紅多段,執行更加精細的屬性動畫。

ValueAnimator

實際上不太想說這個 ValueAnimator,由於它的使用場景確實很少。這裏也不精挑細琢了,大概須要記得:

ViewPropertyAnimatorObjectAnimator 的內部實現其實都是 ValueAnimatorObjectAnimator 更是原本就是 ValueAnimator 的子類,它們三個的性能並無差異。它們的差異只是使用的便捷性以及功能的靈活性。因此在實際使用時候的選擇,只要遵循一個原則就行:儘可能用簡單的。能用 View.animate() 實現就不用 ObjectAnimator,能用 ObjectAnimator 就不用 ValueAnimator。

另外,它們還支持 setDuration(long duration) 設置動畫持續時長以及 setInterpolator() 設置各類「速度設置器」。

速度設置器?

「速度設置器」,簡而言之就是動畫的「速度模型」,這個方法可讓動畫按照你想要的方式進行。通常狀況咱們都直接不設置個,因此下面的瞭解一下就好,甚至跳過也沒事。

簡單科普一下提供的「速度模型」,須要看效果的 點擊這裏

  • AccelerateDecelerateInterpolator

先加速再減速。這是默認的「速度模型」,實際上就像開車同樣,先加速啓動,開一會再減速剎車停下。

  • LinearInterpolator

勻速模型,即動畫是迅速進行的。

  • AnticipateOvershootInterpolator

帶施法前搖和回彈的「速度模型」。

  • DecelerateInterpolator

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

  • AccelerateInterpolator

持續加速。和上面那個剛剛相反。

  • AnticipateInterpolator

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

  • OvershootInterpolator

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

  • AnticipateOvershootInterpolator

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

他孃的,太多啦,就不一一寫完了,真沒啥用處,用到再說嘛。

設置描述動畫生命週期的監聽器

能夠給動畫設置監聽器,分別有兩種設置方式。

  • ViewPropertyAnimator.setListener(AnimatorListener listener)

  • ObjectAnimator.addListener(AnimatorListener listener)

能夠看到,兩種動畫方式設置監聽器有一點不一樣的是一個是 「set」,一個是「add」,但它們的參數都是一致的「AnimatorListener」。

AnimatorListener 有四個回調方法:

/**
         * <p>Notifies the start of the animation.</p>
         *
         * @param animation The started animation.
         */
        void onAnimationStart(Animator animation);

        /**
         * <p>Notifies the end of the animation. This callback is not invoked
         * for animations with repeat count set to INFINITE.</p>
         *
         * @param animation The animation which reached its end.
         */
        void onAnimationEnd(Animator animation);

        /**
         * <p>Notifies the cancellation of the animation. This callback is not invoked
         * for animations with repeat count set to INFINITE.</p>
         *
         * @param animation The animation which was canceled.
         */
        void onAnimationCancel(Animator animation);

        /**
         * <p>Notifies the repetition of the animation.</p>
         *
         * @param animation The animation which was repeated.
         */
        void onAnimationRepeat(Animator animation);

從代碼中能夠很清晰的看出:

  • 在動畫開始執行的時候,調用 onAnimationStart()

  • 在動畫結束後,將調用 onAnimationEnd()

  • 在動畫取消後,將調用 onAnimationCancel()

  • 在動畫重複執行的時候,將調用 onAnimationRepeat()

其中只須要注意兩點:

  • 動畫被 cancel() 取消的時候,依然會調用 onAnimationEnd(),不過是在 onAnimationCancel() 以後。

  • **重複執行動畫,經過 setRepeatMode() / setRepeatCount() 或者 repeat() 方法執行。

但可是!!!ViewProperAnimator 不支持重複。**

動畫的屬性更新監聽器

除了上面設置的動畫生命週期監聽器,咱們還有其餘的方法,好比 ViewPropertyAnimator.setUpdateListener() / ObjectAnimator.addUpdateListener()

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

/**
     * Implementors of this interface can add themselves as update listeners
     * to an <code>ValueAnimator</code> instance to receive callbacks on every animation
     * frame, after the current frame's values have been calculated for that
     * <code>ValueAnimator</code>.
     */
    public static interface AnimatorUpdateListener {
        /**
         * <p>Notifies the occurrence of another frame of the animation.</p>
         *
         * @param animation The animation which was repeated.
         */
        void onAnimationUpdate(ValueAnimator animation);

    }

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

方法的參數是一個 ValueAnimatorValueAnimatorObjectAnimator 的父類,也是 ViewPropertyAnimator 的內部實現,因此這個參數其實就是 ViewPropertyAnimator 內部的那個 ValueAnimator,或者對於 ObjectAnimator 來講就是它本身自己。

小結

仍是作個小結,自定義 View 中咱們使用屬性動畫主要分爲三種方式:

  • ViewPropertyAnimator

  • ObjectAnimator

  • ValueAnimator

使用它們的任一個都不會有性能差別,只需記住一個原則,依次愈來愈難,能用簡單的就用簡單的。

哦,還有一個最重要的原則就是,盯緊「扔物線凱哥」,加入咱們的「HenCoder」大軍吧。

作不完的開源,寫不完的矯情。歡迎掃描下方二維碼或者公衆號搜索「nanchen」關注個人微信公衆號,目前多運營 Android ,盡本身所能爲你提高。若是你喜歡,爲我點贊分享吧~
nanchen

相關文章
相關標籤/搜索