天天看點

Android動畫深入分析-屬性動畫初級用法一、 屬性動畫引入的背景二、屬性動畫三、屬性動畫的xml實作end

一、 屬性動畫引入的背景

1、view動畫的不足之處

1、作用的對象隻能是view

2、隻能播放view的四種動畫或動畫組合(透明漸變、平移、縮放、旋轉)

3、非view對象不能使用view動畫

4、太局限 靈活性差

5、補間動畫還有一個緻命的缺陷,就是它隻是改變了View的顯示效果而已,而不會真正去改變View的屬性。(這點可以給按鈕設定點選事件進行平移動畫測試點選位置)

2、屬性動畫

屬性動畫機制已經不再是針對于View來設計的了。它實際上是一種不斷地對值進行操作的機制,并将值指派到指定對象的指定屬性上,可以是任意對象的任意屬性。我們隻需要告訴系統動畫的運作時長,需要執行哪種類型的動畫,以及動畫的初始值和結束值,剩下的工作就可以全部交給系統去完成了。

3、幾個常用的類

  • Animator 屬性動畫基類
  • ValueAnimator 值動畫
  • ObjectAnimator 對象動畫
  • AnimatorSet 屬性動畫集合

4、幾個類之間關系

(1)動畫基類Animator :

Android動畫深入分析-屬性動畫初級用法一、 屬性動畫引入的背景二、屬性動畫三、屬性動畫的xml實作end
屬性動畫基類

(2)關系類圖

Android動畫深入分析-屬性動畫初級用法一、 屬性動畫引入的背景二、屬性動畫三、屬性動畫的xml實作end

二、屬性動畫

1、ValueAnimator

(1)ValueAnimator簡介

由于Animator是抽象類,ValueAnimator 是直接繼承 Animator的。ValueAnimator還負責管理動畫的播放次數、播放模式、以及對動畫設定監聽器等(Animator的這些方法都在ValueAnimator 實作),确實是一個非常重要的類。是以ValueAnimator 是整個屬性動畫機制當中最核心的一個類。

(2)屬性動畫工作機制

屬性動畫的運作機制是通過不斷地對值進行操作來實作的,而初始值和結束值之間的動畫過渡就是由ValueAnimator這個類來負責計算的。它的内部使用一種時間循環的機制來計算值與值之間的動畫過渡,我們隻需要将初始值和結束值提供給ValueAnimator,并且告訴它動畫所需運作的時長,那麼ValueAnimator就會自動幫我們完成從初始值平滑地過渡到結束值這樣的效果。

(3)ValueAnimator 的使用

通過上文我們了解 屬性動畫可以作用于任何對象,其實也可以不作用對象而直接播放動畫(如下栗子)
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f);
        valueAnimator.setDuration(400);
        valueAnimator.start();
// 這樣就開啟了一個簡單的動畫,表示吧一個值從0變化到1,執行時長300ms。
           
不作用與對象也可以播放動畫?哇真的很強大,可是不作用對象我們運作代碼怎沒看到?怎沒确定動畫播放了?我們可以設定動畫監聽啊!!!栗子如下:
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f);
        valueAnimator.setDuration(400);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = (float) animation.getAnimatedValue();
                Log.i("blabla", "onAnimationUpdate: " + value);
            }
        });
        valueAnimator.start();
        
        // log 如下,可以看到數值從0到1平滑的改變。
        
2019-06-11 10:38:15.289 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.0
2019-06-11 10:38:15.331 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.0
2019-06-11 10:38:15.505 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.36806342
2019-06-11 10:38:15.608 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.7477293
2019-06-11 10:38:15.642 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.8535534
2019-06-11 10:38:15.650 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.89507747
2019-06-11 10:38:15.703 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.9822787
2019-06-11 10:38:15.716 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.99554986
2019-06-11 10:38:15.730 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 1.0
           

ofFloat方法:

* @param values A set of values that the animation will animate between over time.
     * @return A ValueAnimator object that is set up to animate between the given values.
     */
    public static ValueAnimator ofFloat(float... values) {
        ValueAnimator anim = new ValueAnimator();
        anim.setFloatValues(values);
        return anim;
    }
           
這個方法表示改變的值為float類型。參數為可變參數,代表值在這些參數内變化。如上我們設定0-1代表300ms内從0變化到1。假如我們設定0,1,3。數值将0變化到1再變化到3。

ofInt方法:

和ofFloat類似,隻是數值為int類型而不是小數類型。也是比較常用的方法

ofObject方法:

ObjectAnimator 中用的多,在ObjectAnimator 使用中再總結。

其他方法:

  • setStartDelay 設定動畫延遲播放時間
  • setRepeatCount 設定動畫循環次數
  • setRepeatMode 設定動畫循環播放模式(RESTART:重新播放,REVERSE:倒序播放)

2、ObjectAnimator

(1)ValueAnimator 的特點

1、對值操作

2、值平滑的發生變化

3、平時使用場景不多

(2)ObjectAnimator特點

1、對對象的屬性進行操作

2、相比于ValueAnimator,ObjectAnimator可能才是我們最常接觸到的類

3、它其實是繼承自ValueAnimator的,底層的動畫實作機制也是基于ValueAnimator來完成的

方法ofFloat

* @param target The object whose property is to be animated. This object should
     * @param propertyName The name of the property being animated.
     * @param values A set of values that the animation will animate between over time.
     * @return An ObjectAnimator object that is set up to animate between the given values.
     */
    public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
        anim.setFloatValues(values);
        return anim;
    }
    
           

和ValueAnimator 的ofFloat類似,有點小改動。

1、Object target 要操作的對象,對哪個對象進行動畫。

2、String propertyName 要操作對象的屬性,對哪個對象的屬性進行動畫。

3、 float… values 可變參數(值變化範圍,這點和ValueAnimator 的ofFloat的參數一樣)

簡單例子如下:

button = findViewById(R.id.btn);
//         參數1: object 對象
//         參數2: 操作的屬性 (屬性要有get set方法)
//          3-n  :  可變參數 要執行動畫的數值變化範圍
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(button, "rotation", 0f, 360f);
        objectAnimator.setDuration(5000);
        objectAnimator.start();
           

動畫效果:按鈕旋轉360度

有了旋轉rotation,其實我們也可以設定屬性為:

  • alpha(透明度變化)
  • translationX(x軸方向平移)
  • translationY(y軸方向平移)
  • scaleY
  • scaleX
  • 等等
或許我們疑問:ObjectAnimator的ofFloat的第二個參數可以為那些屬性值?上面我們知道可以傳alpha、translationX、translationY、scaleY、scaleX等等。其實我們可以傳入任意的值到ofFloat()方法的第二個參數當中。但事實就是如此。因為ObjectAnimator在設計的時候就沒有針對于View來進行設計,而是針對于任意對象的,它所負責的工作就是不斷地向某個對象中的某個屬性進行指派,然後對象根據屬性值的改變再來決定如何展現出來。

(3)上述按鈕動畫栗子分析

1、其實這段代碼的意思就是ObjectAnimator會幫我們不斷地改變Button對象中rotation屬性的值,從0f變化到360f。然後button對象需要根據rotation屬性值的改變來不斷重新整理界面的顯示,進而讓使用者可以看出旋轉的動畫效果。

2、那麼button對象中是不是有rotation屬性這個值呢?沒有,不僅button沒有這個屬性,連它所有的父類也是沒有這個屬性的!這就奇怪了,button當中并沒有rotation這個屬性,ObjectAnimator是如何進行操作的呢?其實ObjectAnimator内部的工作機制并不是直接對我們傳入的屬性名進行操作的,而是會去尋找這個屬性名對應的get和set方法,是以rotation屬性所對應的get和set方法應該就是(如下代碼)

3、那麼button對象中是否有這兩個方法呢?确實有,并且這兩個方法是由View對象提供的,也就是說不僅button可以使用這個屬性來進行淡入淡出動畫操作,任何繼承自View的對象都可以的。

4、既然rotation 可以那麼我們上述說的alpha等等都可以了

ps:對象要有get set方法才能進行屬性動畫

public void setRotation(float value);
public float getRotation();
           

3、AnimatorSet-屬性動畫集合

(1)控制動畫播放順序的api

  • after(Animator anim) 将現有動畫插入到傳入的動畫之後執行
  • after(long delay) 将現有動畫延遲指定毫秒後執行
  • before(Animator anim) 将現有動畫插入到傳入的動畫之前執行
  • with(Animator anim) 将現有動畫和傳入的動畫同時執行

這幾個api的傳回值都是AnimatorSet.Builder類型執行個體,builder模式鍊式調用(如下play的源碼)

//AnimatorSet的方法
public Builder play(Animator anim) {
        if (anim != null) {
            return new Builder(anim);
        }
        return null;
    }
           

(2)栗子

// 旋轉
        ObjectAnimator rotation = ObjectAnimator.ofFloat(button, "rotation", 0f, 360f);
        // 平移
        float translationX = button.getTranslationX();
        ObjectAnimator translation = ObjectAnimator.ofFloat(button, "translationX", translationX, -500f, translationX);
        // 透明
        ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(button, "alpha", 1f, 0f, 1f);
        // 動畫集合播放上述動畫
        AnimatorSet animatorSet = new AnimatorSet();
        // 先播放 translation 再同時播放rotation、fadeInOut
        animatorSet.play(rotation).with(fadeInOut).after(translation);
        animatorSet.setDuration(3000);
        animatorSet.start();

           

(4)Animator監聽器

動畫怎沒能沒有監聽呢?是以Animator提供了監聽方法addListener(AnimatorListener listener),我們隻需要實作這個listener就行啦。。。。。由于這方法是Animator提供是以屬性動畫通用。
  • AnimatorListener
AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                Log.i("blabla", "onAnimationStart: ");
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                Log.i("blabla", "onAnimationEnd: ");
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                Log.i("blabla", "onAnimationCancel: ");
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                Log.i("blabla", "onAnimationRepeat: ");
            }
        });
           
  • AnimatorListenerAdapter
如上AnimatorListener使用時需要重寫四個方法但是有時候我們可能不需要重寫這麼多,有時我們可能隻需要重寫一個,這時Android提供了一個擴充卡類,叫作AnimatorListenerAdapter,使用這個類就可以解決掉實作接口繁瑣的問題了。(栗子如下)
AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.addListener(new AnimatorListenerAdapter() {
            // 重寫想使用的方法即可
            @Override
            public void onAnimationStart(Animator animation) {
                // todo
            }
        });
           

三、屬性動畫的xml實作

我們可以使用代碼來編寫所有的動畫功能,這也是最常用的一種做法。不過,過去的補間動畫除了使用代碼編寫之外也是可以使用XML編寫的,是以屬性動畫也提供了這一功能,即通過XML來完成和代碼一樣的屬性動畫功能。

1、xml編寫的優缺點

優點:

代碼重用友善

缺點:

編寫相對java代碼麻煩

擴充性不高(比如動态獲得手機資訊就需要java代碼實作)

2、标簽

  • animator 對應代碼中的ValueAnimator
  • objectAnimator 對應代碼中的ObjectAnimator
  • set 對應代碼中的AnimatorSet

3、編寫步驟

首先要在res目錄下面建立一個animator檔案夾
Android動畫深入分析-屬性動畫初級用法一、 屬性動畫引入的背景二、屬性動畫三、屬性動畫的xml實作end

4、栗子

(1)從0到100平滑過渡的動畫

<animator android:duration="3000"
    android:valueFrom="0"
    android:valueTo="1"
    android:valueType="floatType"/>
           

(2)将一個視圖的alpha屬性從1變成0

<objectAnimator
        android:valueFrom="0"
        android:valueTo="1"
        android:valueType="floatType"
        android:propertyName="alpha"/>
           

(3)組合動畫

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <animator
        android:duration="3000"
        android:valueFrom="0"
        android:valueTo="1"
        android:valueType="floatType" />
    <objectAnimator
        android:valueFrom="0"
        android:valueTo="1"
        android:valueType="floatType"
        android:propertyName="alpha"/>
</set>
           

5、 xml動畫資源加載

Animator animator = AnimatorInflater.loadAnimator(this, R.animator.test);
       animator.setTarget(button);
       animator.start();
           

end

參考:

1、安卓開發藝術探索

2、https://blog.csdn.net/guolin_blog/article/details/43536355

屬性動畫中級用法

繼續閱讀