Android Animation 系列——屬性動畫(Property Animation)

万俟霜風發表於2017-12-05

000 屬性動畫簡介

屬性動畫是 Android API level 11(Android 3.0)中新增的動畫框架,功能強大,擴充套件性強。介紹屬性動畫,就需要說明三個問題:

屬性是什麼?

用官方的話說,Property is a field in an object。更進一步解釋,這裡的屬性是指一個物件中具有 setter/getter 方法的變數。

屬性動畫可以做什麼?

一般來說,動畫是一種視覺效果,但是屬性動畫的內容要更廣泛,除了做一些視覺效果之外,屬性動畫還可以用類似動畫的方式默默改變一些資料。當然,最主要的還是實現視覺效果,包括常見的透明度、縮放、平移、旋轉效果,也可以擴充套件出其他的屬性(比如顏色)。

與之前的 View Animation 有什麼區別?

View Animation 是在 API level 1 開始支援的動畫框架,內容只有基本的透明度、縮放、平移、旋轉,且動畫的物件只能是 View。

二者的區別有以下幾點:

  1. 屬性動畫實際改變了動畫目標的屬性值,比如平移一個 View,View 的位置真實發生了改變,而 View Animation僅是改變了螢幕繪製位置,真實位置不變。
  2. 屬性動畫可以作用於沒有繪製到螢幕上的物件。
  3. 屬性動畫可以作用於非 View 物件,也可以製作四類基本動畫之外的動畫效果。
  4. View Animation 的程式碼量更少,效率更高。

001 相關API說明

屬性動畫中新新增的類主要是這些:

property animation framework.jpg

Animator

作為屬性動畫的基類,Animator 提供了動畫最基本的屬性。

僅列出一部分(我覺得)常用的。

Method Name Function
start() 開始播放
cancel() 取消動畫
isRunning() 是否正在播放
addListener 新增監聽回撥
setTarget 設定動畫目標Object
setDuration 設定播放時長,單位:毫秒
setInterpolator 設定插值器

關於插值器的內容本文暫不介紹了。

ValueAnimator

構造方法

//直接建立
    ValueAnimator valueAnimator = new ValueAnimator();
//帶引數建立
    ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.0f, 2.0f);
    // ValueAnimator valueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), Color.RED, Color.GREEN);
    // ...還有ofArgb,ofInt,ofPropertyValuesHolder
複製程式碼

比起 Animator 增加的一些常用方法

Method Name Function
setStartDelay 設定動畫啟動延遲,單位:毫秒
addUpdateListener 新增Value更新的監聽回撥
setRepeatMode 設定重複播放模式,RESTART或REVERSE
setRepeatCount 設定重複播放次數
ObjectAnimtor

構造方法

//直接建立
    ObjectAnimator objectAnimator = new ObjectAnimator();
//帶引數建立
    ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mView, "alpha", 1.0f, 0.7f);
    //...類似的構造方法有很多,就是引數不同,這些引數都可以通過setter方法設定。
複製程式碼

ObjectAnimatior 增加了屬性動畫最基本的方法——設定屬性。

Method Name Function
setProperty 設定動畫目標屬性
setPropertyName 通過name設定動畫目標屬性
setIntValues(int... values) 設定一系列動畫引數,按順序執行
setFloatValues(float... values) 設定一系列動畫引數,按順序執行
setObjectValues(Object... values) 設定一系列動畫引數,按順序執行
AnimatorSet

AnimatorSet 的功能就是把多個各種 Animator 物件整合成一個動畫,有點類似與 ViewGroup。

Method Name Function
playTogether 多個動畫一起播放
playSequentially 多個動畫順序播放

010 使用場景分析

Animator物件

ValueAnimator 的功能很單一,比較像“時間軸”,就是設定一個值,在一段時間內以某種規則變化。這也是 ObjectAnimator 實現動畫的基礎。

舉個例子,通過 VlaueAnimator 改變 View 的顏色:

    private int mColor = Color.RED;
    public ValueAnimator valueAnimator;
//...
//...
    valueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), mColor, Color.rgb(0,0,255));
    valueAnimator.setDuration(3000);
    valueAnimator.setInterpolator(new LinearInterpolator());
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mColor = (int) animation.getAnimatedValue();
            }
        });
複製程式碼

onAnimationUpdate 方法中把變化後的顏色重新整理到 UI 介面就行了。效果是這樣的:

ValueAnimator sample.gif

相比之下 ObjectAnimator 才是屬性動畫中的主角,建立 ObjectAnimator 物件實現動畫需要有幾個要素:

  1. propertyName:要變化的屬性名(String)
  2. target:具有該屬性的 Object 物件
  3. values:對應屬性的變化值,資料型別要和屬性的型別一致

屬性名接受一個 String 型別的引數,就很容易出錯。可以通過輸入 target 的 object 物件,在程式碼提示中找 setter 方法來確定屬性名。View 的屬性名是比較常用的,比如:alpharotationscaleXscaleYtranslationXtranslationYrotationXrotationY等。

舉個例子,網路載入中可能會大量用到的一種loading動畫。

    ObjectAnimator animator = new ObjectAnimator();
    animator.setPropertyName("rotation");
    animator.setTarget(ivLoading);
    animator.setFloatValues(0,360);
    animator.setDuration(900);
    animator.setRepeatMode(ObjectAnimator.RESTART);
    animator.setRepeatCount(ObjectAnimator.INFINITE);
    animator.setInterpolator(new LinearInterpolator());
    animator.start();
複製程式碼

程式碼含義比較清晰,需要注意的是setInterpolator預設的插值器並不是線性的,下面給出兩種效果,左側是 LinearInterpolator ,右側是預設的。

ObjectAnimatior Sample.gif

xml實現

xml 實現動畫是一種比較合理的複用動畫方式,可以有效避免在 Controller 層寫過多隻屬於 View 層的程式碼。

屬性動畫的 xml 檔案需要放在res/animator資料夾下。

語法與 View Animation 差別比較大,大概是這樣子的:

xml animator(官方文件截圖).png

直觀感受就是比 View Animation 的 xml 實現麻煩很多,實際上由於 xml 檔案的限制二者功能上差不多,應該是 View Animation 更加常用一點。(個人感受)

view.animate()

ObjectAnimator 的程式碼寫起來不怎麼好看,因為總是在 objectAnimator.xxx(),比起單獨在Activity中實現某些互動效果,把簡單而常用的動畫效果封裝成工具類會更理想一些。但是互動效果是千變萬化的,總有一些獨特的動畫無法複用。

於是在 API level 12 中,出現了針對 View 的屬性動畫 ViewPropertyAnimtor。ViewProperty 中封裝了 View 相關的常用動畫引數的設定以及多種回撥,並用 ObjectAnimator 實現了動畫效果,對外提供了相當簡單易懂的流式 API,使動畫的程式碼也可以寫的很爽。

使用方法:

  1. 獲取 ViewPropertyAnimator 物件

ViewPropertyAnimator 沒有 public 的構造方法,只能通過 View 物件的 animate() 方法獲得。使用的 View 物件就是動畫的 target。

ViewPropertyAnimator 物件是會重複使用的,多次呼叫'animate()'只會建立一個 ViewPropertyAnimator。

  1. 設定動畫引數

相關的 API 名稱都很明確,就不一一介紹效果了

ViewPropertyAnimator API.png

ViewPropertyAnimator API.png

  1. 設定回撥(可選)

就是setListener方法。其實所有的動畫都可以設定 Listener ,只是在 ViewPropertyAnimator 中更加重要,因為從 API 可以看出每一種動畫只能傳入一個引數,如果需要同一種動畫多段執行,就只能通過監聽動畫結束脩改引數值再開始動畫。

setListener 方法接收一個 Animator.AnimatorListener 介面的例項,可以直接建立 Animator.AnimatorListener 例項實現所有方法,也可以建立 AnimatorListenerAdapter 只重寫需要的方法。

ViewPropertyAnimator 的複用同樣會影響 Listener,如果是同一個 View 的多個動畫且不相關,需要在不需要 Listener 的動畫中呼叫setListener(null)

這裡也應該舉個例子,不過沒什麼好的想法,姑且再寫一遍 loading 動畫,就當對比一下兩種 API 格式吧。(kotlin程式碼,對比一下設定動畫的 API 就好了)

ivLoadingRight.setOnClickListener {
    ivLoadingRight.animate()
            .rotationBy(360f)
            .setDuration(800)
              .setInterpolator(LinearInterpolator())
            .setListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator?) {
                    super.onAnimationEnd(animation)
                    ivLoadingRight.animate()
                            .rotationBy(360f)
                            .setDuration(800)
                              .setInterpolator(LinearInterpolator())
                            .start()
                }
            }).start()
複製程式碼

011 結語

因為我並沒有做過太多的動畫效果,剛開始寫的時候只想總結一下各種方法的用法和效果,然而那樣就會不能避免的翻譯官方文件,且內容雜亂,不易整理 demo。於是先寫了一些簡單的動畫效果,依據實際程式碼反向整理了這篇文章。

文中 gif 圖對應程式碼都在示例工程(AnimatorSample)中,地址:https://github.com/xhd-Git/Samples

相關文章