Android動畫效果之初識Property Animation(屬性動畫)

總李寫程式碼發表於2016-08-22

前言:

     前面兩篇介紹了Android的Tween Animation(補間動畫) Android動畫效果之Tween Animation(補間動畫)、Frame Animation(逐幀動畫)Android動畫效果之Frame Animation(逐幀動畫)(二),其實總結前兩個的根本目的就是為了學習今天的主角Property Animation(屬性動畫)。其實在Android最早期只提供了前兩種動畫方式,在Android 3.0才引入了屬性動畫,谷歌為何要引入屬性動畫呢?今天我們來總結學習一下。

     其他幾種動畫效果:

Property Animation產生的背景:

    由於Tween Animation(補間動畫)只能實現簡單的四種的動畫(alpha、scale、rotate、translate),要想實現比較複雜的動畫就難以滿足需求,而且補間動畫只是改變了View物件繪製的位置,而沒有改變View物件本身,比如View形狀的變換,如大小的縮放,透明度的改變,位置的改變,其實本身並沒有改變,舉個例子就好比孫悟空靈魂出竅一樣,雖然已經上天入地,其實肉體還在那裡一動不動,我們開發過程中的經常遇見的就是translate之後事件還在原地。如果要實現既要有動畫效果又要使得View本身得到真正改變,那就要藉助屬性動畫了,這也是屬性動畫引入的原因。它能夠更加靈活的實現各種效果,不僅限於類似補間動畫實現的哪幾種效果。

Property Animation相關類

   屬性動畫,根據字面理解可以通過修改物件的屬性值以達到動畫效果。

類名 用途
ValueAnimator 屬性動畫主要的計時器,也計算動畫後的屬性的值,動畫的執行類
ObjectAnimator   ValueAnimator的一個子類,允許你設定一個目標物件和物件的屬性進行動畫,動畫的執行類
AnimatorSet 提供組織動畫的結構,使它們能相關聯得執行,用於控制一組動畫的執行
AnimatorInflater  使用者載入屬性動畫的xml檔案
Evaluators  屬性動畫計算器,告訴了屬性動畫系統如何計算給出屬性的值
Interpolators 動畫插入器,定義動畫的變化率

 上面幾個重要類之間的關係如下圖所示:

 

今天先通過最簡單最容易理解的ObjectAnimator來學習總結。

ObjectAnimator:

   ValueAnimator的一個子類,允許你設定一個目標物件和物件的屬性進行動畫。當這個類計算好一個動畫的新值後,相應的會更新其屬性。大多數時候你都會想用ObjectAnimator,因為它使得動畫值到目標物件的處理更簡單了。

1.)以實現一個View透明漸變效果為例進行說明

xml實現方式:

這裡需要注意是的屬性動畫檔案存放目錄為res/animator

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:propertyName="alpha"
    android:repeatCount="1"
    android:repeatMode="reverse"
    android:startOffset="200"
    android:valueFrom="0.0"
    android:valueTo="1.0"
    android:valueType="floatType" />

duration 表示動畫執行的時間

propertyName 表示修改的物件的哪個屬性值,這裡是透明度

valueFrom 表示從哪個狀態值開始動畫

valueTo 表示到哪個狀態值結束動畫

valueType 型別估值,主要用於設定動畫操作屬性的值

repeatMode 表示重複的模式 reverse表示

repeatCount 動畫重複的計數,動畫將會執行該值+1次

repeatMode 動畫重複的模式,reverse為反向,當第偶次執行時,動畫方向會相反。restart為重新執行,方向不變

startOffset, 動畫多次執行的間隔時間,如果只執行一次,執行前會暫停這段時間,單位毫秒 

interpolator 指定動畫插入器

通過上面的xml屬性可以看出和補間動畫基本上一致,然後通過AnimatorInflater 來載入xml中的動畫

Animator anim = AnimatorInflater.loadAnimator(this, R.animator.animator_alpha);
anim.setTarget(imageView);
anim.start();

當然也可以通過純Java程式碼的方式實現

ObjectAnimator alphaAnimation = ObjectAnimator.ofFloat(imageView, "alpha", 0f, 1f);
    alphaAnimation.setDuration(500);
    alphaAnimation.setRepeatCount(0);
    alphaAnimation.setRepeatMode(ValueAnimator.REVERSE);
    alphaAnimation.setStartDelay(200);
    alphaAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
    alphaAnimation.start();

對於java程式碼實現,ObjectAnimator 提供了以下幾個方法:ofFloat(),ofInt(),ofObject(),ofArgb(),ofPropertyValuesHolder()這幾個方法都是設定動畫作用的元素、作用的屬性、動畫開始、結束、以及中間的任意個屬性值。

其他舉例:

縮放動畫:

xml:

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
  android:duration="500"
  android:propertyName="scaleX"
  android:repeatCount="1"
  android:repeatMode="reverse"
  android:valueFrom="1.0"
  android:valueTo="1.5"
  android:valueType="floatType" />

java程式碼:

 ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 1.5f);
   scaleXAnimator.setDuration(500);
   scaleXAnimator.setRepeatCount(1);
   scaleXAnimator.setRepeatMode(ValueAnimator.REVERSE);
   scaleXAnimator.start();
旋轉動畫:

 xml:

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:propertyName="rotation"
    android:repeatCount="1"
    android:repeatMode="reverse"
    android:valueFrom="0"
    android:valueTo="360"
    android:valueType="floatType" />

java程式碼:

 ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "rotation", 0f, 360f);
    objectAnimator.setDuration(500);
    objectAnimator.setRepeatCount(1);
    objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
    objectAnimator.start();
平移動畫:

xml:

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:propertyName="translationX"
    android:repeatCount="1"
    android:repeatMode="reverse"
    android:valueFrom="0"
    android:valueTo="100"
    android:valueType="floatType" />

java程式碼:

 ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 100f);
    objectAnimator.setDuration(500);
    objectAnimator.setRepeatCount(1);
    objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
    objectAnimator.start();

2.)如何實現一個組合動畫

    舉例我們同時對一個控制元件進行寬高兩個維度的縮放

  方式一:使用AnimatorSet
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together">
    <objectAnimator
        android:duration="500"
        android:propertyName="scaleX"
        android:repeatCount="1"
        android:repeatMode="reverse"
        android:valueFrom="1.0"
        android:valueTo="1.5"
        android:valueType="floatType" />
    <objectAnimator
        android:duration="500"
        android:propertyName="scaleY"
        android:repeatCount="1"
        android:repeatMode="reverse"
        android:valueFrom="1.0"
        android:valueTo="1.5"
        android:valueType="floatType" />

</set>

載入xml動畫

    Animator anim = AnimatorInflater.loadAnimator(this, R.animator.animator_scale);
      anim.setTarget(imageView);
      anim.start();

純Java程式碼實現:

AnimatorSet animatorSet = new AnimatorSet();

    ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 1.5f);
    scaleXAnimator.setDuration(500);
    scaleXAnimator.setRepeatCount(1);
    scaleXAnimator.setRepeatMode(ValueAnimator.REVERSE);
    scaleXAnimator.start();

    ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(imageView, "scaleY", 1f, 1.5f);
    scaleYAnimator.setDuration(500);
    scaleYAnimator.setRepeatCount(1);
    scaleYAnimator.setRepeatMode(ValueAnimator.REVERSE);

    animatorSet.playTogether(scaleXAnimator, scaleYAnimator);
    animatorSet.start();

上述程式碼通過playTogether函式實現兩個動畫同時執行,如果不想同時執行,也可以呼叫play函式返回AnimatorSet.Builder例項,AnimatorSet.Builder提供瞭如下幾個函式用於實現動畫組合:

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

也可以呼叫playSequentially函式實現分佈執行動畫。

  方式二:使用PropertyValuesHolder
PropertyValuesHolder scaleXValuesHolder = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 1.5f);
PropertyValuesHolder scaleYValuesHolder = PropertyValuesHolder.ofFloat("scaleY", 1.0f, 1.5f);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(imageView, scaleXValuesHolder, scaleYValuesHolder);
    objectAnimator.setDuration(500);
    objectAnimator.setRepeatCount(1);
    objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
    objectAnimator.start();

通過這種方式只能實現同時執行的動畫組合相比AnimatorSet就沒那麼豐富了,PropertyValuesHolder 提供的函式方法有如下幾種:ofInt()、ofFloat()、ofObject()、ofKeyframe()。

方式三:使用ViewPropertyAnimator
 ViewPropertyAnimator viewPropertyAnimator=imageView.animate();
 viewPropertyAnimator.scaleXBy(1.0f).scaleX(1.5f).scaleYBy(1.0f).scaleY(1.5f).setDuration(500).start();

多屬性動畫,作用於View,能夠實現的動畫相對單一,只能實現比如縮放,透明度改變,平移、旋轉等,具體函式名字:平移 translationX,translationY, X,Y,縮放 scaleX,scaleY, 旋轉 rotationX, rotationY,透明度 alpha

3.)設定動畫監聽器

有時候我們可能要在某一個動畫執行之前 或者動畫結束之後進行一些其他的操作,這個時候就要藉助動畫監聽器了。

    objectAnimator.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animation) {
        //TODO 動畫開始前的操作
    }

    @Override
    public void onAnimationEnd(Animator animation) {
        //TODO 動畫結束的操作
    }

    @Override
    public void onAnimationCancel(Animator animation) {
       //TODO 動畫取消的操作
    }

    @Override
    public void onAnimationRepeat(Animator animation) {
        //TODO 動畫重複的操作
    }
    });

如果我們需要簡單動畫執行過程中的變化可以使用AnimatorUpdateListener

 objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float value = (float) animation.getAnimatedValue();
        //可以根據自己的需要來獲取動畫更新值。
        Log.e("AnimatorUpdateListener", "the animation value is " + value);
    }
    });

總結:

   本篇主要先簡單認識一下屬性動畫,以及利用屬性動畫實現補間動畫。後續會對屬性動畫進行進一步的學習。

相關文章