天天看點

Android--幀動畫

版權聲明:本文為部落客原創文章,轉載請标明出處。 https://blog.csdn.net/chaoyu168/article/details/51194749

講解一遍如何制作空心心形到實心心形的過渡動畫,然後講解與之反向的動畫。效果如下:

圖檔序列

幀動畫的原理很簡單:就像老式電影膠卷那樣,快速掠過一些列的圖檔,“幀”其實就是一張圖檔,是以建立一個自定義幀動畫的第一步就是建立圖檔序列。

我們有兩種選擇:使用xml的drawable(比如shape drawable)或者是使用實際的圖檔。簡便起見,我們直接使用下面的一些列PNG圖檔:

在産品級的應用中,我們還需要保證圖檔尺寸可以适配不同的螢幕分辨率。但是現在,我們将所有的圖檔都扔到res/drawable-mdpi目錄下完事。我推薦圖檔的命名采用自描述的方式,比如ic_heart_0.png, ic_heart_1.png以此類推。。。這樣我們就不需要檢視圖檔就知道圖檔的順序。

但誰叫我是屌絲呢,我選擇将圖檔按照填充的百分比程度命名。

XML Drawable

現在我們已經有了要掠一遍的圖檔,下一步就是為動畫定義一個XML的Drawable,我們又遇到了兩種選擇:Animation-list和Animated-selector。

Animation-List

Animation-list是幀動畫的預設選擇,因為在API 1的時候就有了,同時它非常簡單。就是簡單的掠過指定順序和持續時間的圖檔序列。

這裡是填充到實心效果的Animation-list的例子,在res/drawable/animation_list_filling.xml中:

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

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_0"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_25"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_50"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_75"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_100"/>

</animation-list>
           

清單中的每一個item都指向圖檔序列中的一張圖檔。我們隻需把它們的順序擺放正确并且添加一個毫秒為機關的持續時間即可。

下面是實作變為空心效果的Animation-list,在res/drawable/animation_list_emptying.xml中:

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

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_100"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_75"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_50"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_25"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_0"/>

</animation-list>           

你可能注意到了,在兩個代碼片段中都有android:oneshot=”true”,這是animation-list的一個屬性,表示播放完一次動畫之後便停止動畫。如果這個屬性值設定為“false”,則動畫會重複播放。

在實際産品中,500毫秒時間太長,但是作為示範,我有意誇大了這個時間。還有一點,5幀圖檔對于産生流暢的過渡來說還是不夠多。使用多少幀以及每幀的顯示時間取決于個人。作為參考,我覺得15毫秒的15幀圖檔就可以非常流暢了。

Animated-Selector

Animated-selector要稍微複雜一些,因為它是基于狀态的。根據View的狀态(比如選中與激活狀态),selector将使用提供的Transition來過渡到正确的狀态。Animated-selector隻在Lollipop上有效,是以我們需要在-v21 package中也定義一個xml。

下面是一個Animated-selector的例子,放在res/drawable-v21/selector.xml中:

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

    <item
        android:id="@+id/on"
        android:state_activated="true">
        <bitmap
            android:src="@drawable/ic_heart_100"/>
    </item>

    <item
        android:id="@+id/off">
        <bitmap
            android:src="@drawable/ic_heart_0"/>
    </item>

    <transition
        android:fromId="@+id/on"
        android:toId="@+id/off"
        android:drawable="@drawable/animation_emptying">
    </transition>

    <transition
        android:fromId="@id/off"
        android:toId="@id/on"
        android:drawable="@drawable/animation_filling">
    </transition>

</animated-selector>           

仔細觀察它是如何将前面定義的Animation-list引用為Transition的。

這個animated-selector沒有任何問題,但是我們需要考慮非Lollipop裝置。我們在res/drawable/selector.xml中定義一個沒有動畫的selector:

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

    <item
        android:state_activated="true">
        <bitmap android:src="@drawable/ic_heart_100"/>
    </item>

    <item
        android:state_activated="false">
        <bitmap android:src="@drawable/ic_heart_0"/>
    </item>

</selector>           

現在我們的selector在任意裝置上都可以工作。因為我們隻使用了一般的selector,如果在Lollipop以前的裝置上,animated-selector将直接跳過過渡動畫,直接到結束狀态。當然Lollipop裝置是有我們在animated-selector中定義的過渡效果的。

在上面的代碼片段中,animated-selector隻關注了android:state_activated屬性。就如一般的selector一樣,我為不同的狀态定義了不同的item,但不同的是,我們還定義了不同狀态間動畫過渡的transition。在這個例子中,我直接将transition指向前面定義好了的animation-list。

現在我們有了四個xml檔案:一個充到實心效果的xml,實心到空心的xml,兩個在空心實心之間切換的xml。

設定ImageView

現在可以設定一些圖檔來玩了。我們這裡有三個ImageView,分别對應前面定義的三個XML Drawable。将下面的代碼放到你的Activity的布局中:

<ImageView
    android:id="@+id/imageview_animation_list_filling"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/animation_list_filling"
    />

<ImageView
    android:id="@+id/imageview_animation_list_emptying"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/animation_list_emptying"
    />

 <ImageView
    android:id="@+id/imageview_animated_selector"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/selector"
    />           

這隻是幾個id唯一,背景為我們定義的xml Drawable的ImageView。

開始動畫

開始動畫的方式在兩種實作方法中是不一樣的,我們先從animation-list開始:

在Activity中,我們得到ImageView的引用,然後開始動畫。如下:

ImageView mImageViewFilling = (ImageView) findViewById(R.id.imageview_animation_list_filling);
((AnimationDrawable) mImageViewFilling.getBackground()).start();           

下面是效果:

接下來是它的搭檔-反向過程(除了id都是一樣的)

ImageView mImageViewEmptying = (ImageView) findViewById(R.id.imageview_animation_list_emptying);
((AnimationDrawable) mImageViewEmptying.getBackground()).start();           

效果如下:

這些代碼可以放在onCreate(在Activity開始的時候自動開始)或者一個OnClickListener(等待使用者觸發)中,取決于你自己!

當使用Animated-selector的時候,動畫将在狀态條件滿足selector的時候被觸發。在我們這個簡單的例子中,我們在Activity的onCreate方法中為ImageView添加一個click listener:

mImageViewSelector.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mImageViewSelector.setActivated(!mImageViewSelector.isActivated());
    }
});           

當使用者點選心形,它将會根據目前的狀态在實心與空心之間切換,下面是我的心形循環顯示的gif圖:

繼續閱讀