1. 程式人生 > >通過原始碼,手把手帶你學屬性動畫(三)

通過原始碼,手把手帶你學屬性動畫(三)

主要內容:上篇側重介紹了ofFloat()方法,以及與動畫相關的方法、監聽,本節將繼續介紹剩下的 ofObject() 和 ofPropertyValuesHolder() 方法,以及相關的 TypeEvaluator 和 PropertyValuesHolder。

下面直接開始講解。

1. ofObject() 與 TypeEvaluator

在介紹ofObject()之前,先來說說TypeEvaluator,可以理解為型別計算器,一般動畫效果不會用到,但是有必要了解一下,一來以備不時之需,二來有利於我們後面讀懂原始碼。

1.1 型別計算器-TypeEvaluator

Evaluators allow developers to create animations on arbitrary property types, by allowing them to supply custom evaluators for types that are not automatically understood and used by the animation system.

大概意思是:對不能被動畫系統自動識別且使用的型別提供自定義估值器,以允許開發者對任意型別的屬性值實施動畫

概括來說:告訴屬性動畫系統如何從開始值過渡到結束值!給其一個動畫進度,返回一個當前進度下對應的屬性值,可以是一個數值,也可以是一個點,或者更復雜的資料型別。

TypeEvaluator 只有一個介面方法,我們在自定義型別計算時需要覆寫該方法:

T evaluate(float fraction, T startValue, T endValue)

該方法的返回值、開始值、結束值均使用泛型宣告,說明該介面不關心具體的值型別,我們只需要根據當前動畫進度fraction,來計算改變後的屬性值並返回即可。

其一般計算過程可簡化為:返回值 = 開始值 + (終點值-開始值) * 進度

系統內建了7種類型計算器:

7種計算器

系統的型別計算器,都根據實際資料型別覆寫了evaluate()方法,包括整形(IntEvaluator)、浮點型(FloatEvaluator)、顏色(ArgbEvaluator)、點(PointFEvaluator)等型別,已基本滿足實際開發的大部分需求,只是在特殊需求下我們可能需要自定義。

強烈建議大家去看看各個類的 evaluate() 方法實現,就不再一一介紹了,一看就懂。

下面我們介紹 ofObject() 的使用,同時會講解如何如何自定義 TypeEvaluator。

1.2 ofObject()使用

在上篇介紹 ofFloat() 時,因為我們明顯是對 float 資料型別做動畫,所以系統預設幫我們指定了 FloatEvaluator,在後面的原始碼分析中會帶大家看的。ofArgb() 與 ofInt() 同理。

現在我們想對點(Point)型別做動畫,然而我們沒有發現 ofPoint() 之類的方法,這就尷尬了!別急,系統為我們提供了 ofObject() 方法,以支援任意型別的資料,這個好!但是,隨之而來有個問題:

既然是任意資料型別,那麼系統肯定不知道你傳的是啥,也就是上面說的“無法自動識別”,那麼怎麼給你做動畫?

比如根據時間,系統知道動畫進行到一半了,你用 ofFloat(0f, 100f),系統按動畫進度能算出來是 50,但是你對點(Point)做動畫,從p1(0,0)到p2(100,100),用 ofObject(p1,p2),系統咋給你算?

所以,使用 ofObject()就需要搭配上面講的 TypeEvaluator,別忘了他的職責:告訴屬性動畫系統如何從開始值過渡到結束值

這裡寫圖片描述

上程式碼!下面,我們演示如何從一個點動畫過渡到另一個點,此處用PointF型別表示點,表示座標值是float型別的。

我們自然而然會想到使用系統內建的 PointFEvaluator,但由於其需要在LOLLIPOP版本(即Android 5.0)以上才可以使用,所以為了相容,我們仿照PointFEvaluator自定義一個MyPointFEvaluator,如下:

public class MyPointFEvaluator implements TypeEvaluator<PointF> {
    PointF 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;

        // 該方法在動畫過程中的每一幀都會呼叫,
        // 使用此舉以避免重複建立PointF物件
        if (null == pointF){
            pointF = new PointF();
        }
        pointF.set(x,y);
        return pointF;
    }
}

evaluate(fraction,startValue,endValue)方法的三個引數是系統所知道,系統不知道的是如何根據進度,以及開始和結束的值,計算當前值!

那我們就需要自己實現evaluate()方法體,告訴系統要怎麼算,並最後返回!程式碼如上所示,感受一下吧!

接下來,使用ofObject實現從點startPoint(0f, 0f)動畫過渡到endPoint(5f, 5f),程式碼如下:

public static void anim1(){
    //定義動畫的值範圍
    PointF startPoint = new PointF(0f, 0f);
    PointF endPoint = new PointF(5f, 5f);
    ValueAnimator valueAnimator =
            ValueAnimator.ofObject(new MyPointFEvaluator(), startPoint, endPoint);
    //設定動畫時長
    valueAnimator.setDuration(100);
    //新增對值的監聽,獲取值
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            PointF pointF = (PointF) animation.getAnimatedValue();
            Log.d("ruicbAndroid", "onAnimationUpdate:"+ pointF.toString());
        }
    });
    //啟動動畫
    valueAnimator.start();
}

以上程式碼我們已經比較熟悉了,與ofFloat()的用法類似,不再介紹。具體的列印結果不再貼上。

2. ofPropertyValuesHolder() 與 PropertyValuesHolder

同樣,我們先看看 PropertyValuesHolder。

2.1 PropertyValuesHolder

在屬性動畫的原始碼實現中,PropertyValuesHolder 起到了關鍵作用,其負責持有物件的屬性和值。有關該類的作用,官方文件 註釋如下:

PropertyValuesHolder objects can be used to create animations with ValueAnimator or ObjectAnimator that operate on several different properties in parallel.

意思是:PropertyValuesHolder 可以被 ValueAnimator 或 ObjectAnimator用來建立動畫,以同時操作多個不同屬性。

我們可以使用 ofPropertyValuesHolder(PropertyValuesHolder… holders)方法,來實現對多個屬性值同時進行動畫。具體的使用,將在介紹 ObjectAnimator 時介紹,此處暫不例舉。

下面先看看如何在 ofPropertyValuesHolder() 方法中使用 PropertyValuesHolder。

2.2 ofPropertyValuesHolder()

該方法主要作用就是:支援我們同時對多個屬性進行動畫

其使用與其他方法無異,不再詳細介紹,只給出建立動畫的關鍵程式碼,感興趣的自行列印結果看看。我將在介紹ObjectAnimator時再演示該方法的作用,在此僅給出簡單的示例,你只需要知道有這個方法就好了。

PropertyValuesHolder holder = PropertyValuesHolder.ofFloat("", 0f, 5f);
ValueAnimator valueAnimator =
        ValueAnimator.ofPropertyValuesHolder(holder);

PropertyValuesHolder.ofFloat(“”, 0f, 5f),第一個引數表示屬性,在此傳空,在介紹ObjectAnimator再介紹該引數。

3.總結

本文主要是對上文的一個補充介紹,如果你認真看完,肯定會有收穫!至此,有關構造 ValueAnimator 物件的工廠方法已經介紹完畢,並介紹了一些與動畫相關的方法。

要知道,在實際開發中,我們使用 ObjectAnimator 更多一些,我為什麼還會在 ValueAnimator 上講這麼多呢?原因有二:

  • ObjectAnimator 繼承自 ValueAnimator,ObjectAnimator
    實現動畫的核心仍然是藉助ValueAnimator,所以理解ValueAnimator將更加有利於掌握ObjectAnimator;
  • 在此處介紹了一些通用API,等後期介紹ObjectAnimator 時,我們就可以專心實現一些動畫效果,而不用再糾結於介紹API了;

下篇我們一起來學習一下動畫中的插值器!

掃描下方二維碼,關注我的公眾號,及時獲取最新文章推送!