天天看點

Android 三種動畫的總結

在看動畫相關的代碼的時候看到過 anim,animator 目錄,資源檔案中的有

<set>

作為根節點的,也有

<animate-list>

作為根節點的。雖然知道它們這是跟動畫有關的,但是卻不知道在代碼中應該怎麼使用它們而且也不知道還可以怎麼寫。是以這篇部落格是對 Android 中的 3 種動畫進行一次 “鳥瞰”,對它們進行一次梳理。

本部落格中的内容來自:

https://developer.android.com/guide/topics/resources/animation-resource.html

https://developer.android.com/guide/topics/graphics/view-animation.html

https://developer.android.com/guide/topics/graphics/drawable-animation.html

https://developer.android.com/guide/topics/graphics/prop-animation.html

概述

Android 将動畫分成了兩大類:

  • 屬性動畫(Property Animation)
  • View 動畫(View Animation)

View 動畫又分成了兩類:補間動畫(Tween Animation)跟幀動畫(Frame Animation)。

屬性動畫

基類: Animator

資源檔案所在路徑: res/animator/filename.xml

文法:

<set
  android:ordering=["together" | "sequentially"]>

    <objectAnimator
        android:propertyName="string"
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["repeat" | "reverse"]
        android:valueType=["intType" | "floatType"]/>

    <animator
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["repeat" | "reverse"]
        android:valueType=["intType" | "floatType"]/>

    <set>
        ...
    </set>
</set>
           

根節點隻能是

<set>

,

<objectAnimator>

, 或者

<animator>

<set>

中可以嵌套

<set>

這三種類型分别對應的類為:AnimatorSet,ObjectAnimator 跟 ValueAnimator 。

應用動畫:

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.anim.property_animator);
set.setTarget(myObject);
set.start();
           

插值器: TimeInterpolator

ViewPropertyAnimator

為了更加友善的使用屬性動畫,Android 提供了該類。該類可以對 View 的多個屬性同時進行動畫操作。

相較于 ObjectAnimator,使用該類更加簡潔,可讀性更高,而且在涉及到多個屬性時比前者的效率更高。

下面舉個例子,同時移動 View 的 x 跟 y 軸坐标:

使用多個 ObjectAnimator 實作:

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
           

使用一個 ObjectAnimator 實作:

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
           

使用 ViewPropertyAnimator 實作:

補間動畫

基類: Animation

資源檔案所在路徑: res/anim/filename.xml

文法:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@[package:]anim/interpolator_resource"
    android:shareInterpolator=["true" | "false"] >
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float" />
    <translate
        android:fromXDelta="float"
        android:toXDelta="float"
        android:fromYDelta="float"
        android:toYDelta="float" />
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />
    <set>
        ...
    </set>
</set>
           

根節點隻能是

<alpha>

,

<scale>

,

<translate>

,

<rotate>

, 或者

<set>

<set>

中可以嵌套

<set>

分别對應的類型為 XxxAnimation 跟 AnimationSet 。補間動畫提供的動畫很有限,隻有上面這幾種。

插值器: Interpolator

因為 Interpolator 繼承自 TimeInterpolator,是以補間動畫中提供的插值器也可以在屬性動畫中使用。

設定插值器的值:

Android 内置了多個插值器,有些插值器提供了一些屬性,在使用它們的時候可以給這些屬性進行指派。比如 AccelerateInterpolator 提供了

factor

屬性;cycleInterpolator 提供了

cycles

屬性。

首先在 res/anim/ 目錄下建立 xml 檔案

文法如下:

<?xml version="1.0" encoding="utf-8"?>
<InterpolatorName xmlns:android="http://schemas.android.com/apk/res/android"
    android:attribute_name="value"
    />
           

需要注意的是,插值器的名稱開頭首字母必須為小寫。

舉個栗子:

<?xml version="1.0" encoding="utf-8"?>
<overshootInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
    android:tension="7.0"
    />
           

小貼士:

有時候 AS 的代碼提示功能并不能提示出插值器中有哪些屬性,這時候就可以這樣做:

1. 打開系統的 attrs.xml 檔案

2. 搜尋要使用的插值器的名字

這時候就可以看到該插值器提供的所有屬性了。

應用動畫:

ImageView image = (ImageView) findViewById(R.id.image);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
image.startAnimation(animation);
           

調用 startAnimation() 會立刻執行動畫,可以調用 Animation 的 setStartTime() 來設定動畫的開始時間,然後在調用 View 的 setAnimation() 來添加動畫。

幀動畫

基類: AnimationDrawable

資源檔案所在路徑: res/drawable/filename.xml

文法:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot=["true" | "false"] >
    <item
      android:drawable="@[package:]drawable/drawable_resource_name"
      android:duration="integer" />
</animation-list>
           

根節點必須為

<animation-list>

,包含一個或者多個

<item>

onshot 為 true 表示動畫隻播放一次。

item 中的 drawable 屬性表示該幀要顯示的圖像,duration 屬性表示該幀顯示的時間

應用動畫:

ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
rocketImage.setBackgroundResource(R.drawable.rocket_thrust);

rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
rocketAnimation.start();
           

如果想要在 Activity 啟動以後就立刻顯示動畫,不要在 onCreate() 中執行,因為此時 AnimationDrawable 還沒有完全的綁定到 Window 中。正确的做法是在 onWindowFocusChanged() 方法中開啟動畫。

下面給出一個完整的栗子:

先來看看效果圖:

Android 三種動畫的總結

首先需要圖檔資源

Android 三種動畫的總結
Android 三種動畫的總結
Android 三種動畫的總結

先将它們放置到 drawable 目錄下,依次命名為 run1,run2,run3

然後在 drawable 目錄下建立一個 xml 檔案,命名為 run.xml:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">

    <item android:drawable="@drawable/run1" android:duration="100"/>
    <item android:drawable="@drawable/run2" android:duration="100"/>
    <item android:drawable="@drawable/run3" android:duration="100"/>

</animation-list>
           

然後編寫布局檔案,修改 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>
           

很簡單,隻有一個 ImageView 。

最後就是讓他動起來,修改 MainActivity.java

public class MainActivity extends AppCompatActivity {

    private ImageView mImageView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mImageView = (ImageView) findViewById(R.id.image);
        mImageView.setBackgroundResource(R.drawable.run);
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        if (hasFocus) {
            ((AnimationDrawable) mImageView.getBackground()).start();
        } else {
            ((AnimationDrawable) mImageView.getBackground()).stop();
        }
    }
}
           

屬性動畫跟 View 動畫的比較

  1. View 動畫隻能用在 View 上,并且支援的操作很少,隻有 scale,translate,rotate 跟 alpha 這 4 種。而屬性動畫可以作用在任意一個對象的任意一個屬性上。
  2. View 動畫并沒有改變 View 的屬性,比如使用 View 動畫将 View 從 A 點 移動到了 B 點以後,實際上 View 還是位于 A 點,B 點隻是它的 “影子” 而已。如果這時候去點選 B 點處的 View 是沒有任何反應的。而使用屬性動畫就會真實的改變 View 屬性。
  3. View 動畫相比起屬性動畫,使用起來會簡單一些。如果 View 動畫已經可以滿足需求則沒有必要使用屬性動畫。最好的方式就是根據不同的場景選擇适合的動畫。