天天看點

Android開發之Frame動畫(幀動畫)

學必求其得,業必貴其專精。——章學成

我們學習的根本是懂得怎樣為人處世,而對于我們的專業一定要堅持不懈的學習讓其達到精益求精的地步,這樣我們才能在這個技術層出不窮的社會上立足,前進。      

 接下來就進入正題 如有謬誤歡迎批評指正,如有疑問歡迎留言,謝謝。  

今天我們就來學習一下Android中的Frame動畫,在學習這些基礎的東西我們一定要參考谷歌給我們的文檔,因為谷歌的文檔是最權威的講解。官網給出的Frame Animation動畫的定義

Frame動畫:包含一個接一個的将要顯示的圖檔資源,這是一個傳統的動畫,它建立一個不同的圖像序列,有順序 的播放,就像一卷膠卷,我們稱為幀動畫。

從官網給出的定義我們不難看出其實Frame 動畫就是一系列的圖檔的按照指定的順序播放的過程,Frame動畫可以被定義在XML中也可以,在代碼中來實作。如果定義在XML中我們可以放在res/drawable/filename.xml或者res/anim/finename.xml,如果完全由代碼實作的話,就要用到AnimationDrawable對象。      
1.将動畫定義在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>元素

. <android:oneshot> boolean類型.  如果為true則動畫隻播放一次,如果為false則循環播放動畫,如果不設定則預設為fasle.

<item> 一幀動畫,必須有一個

<animation-list>父節點. <item>節點中的屬性android:drawable此幀動畫所對應的圖檔資源,android:duration此幀動畫播放所需要的時間,機關為毫秒。
在說幀動畫的例子之前之前我們來說一下使用幀動畫所需注意的事項 官網中明确指出在調用 AnimationDrawable.start()方法時 不能在Activity的onCreate()方法中調用,因為AnimationDrawable的start方法時,視窗Window對象還沒有完全初始化, AnimationDrawable不能完全追加到視窗Window對象中,那 我們怎麼解決這個問題呢?官網給出的建議是在Activity的onWindowFocusChanged方法(如果對此方法不熟可以看此部落格http://blog.csdn.net/dmk877/article/details/45059261)中去掉用 AnimationDrawable.start()方法,因為onWindowFocusChanged在Activity視窗獲得或失去焦點時調用,例如建立時首次展示在使用者面前,是以在調用onWindowFocusChanged方法時視窗已經初始化完全了。 但是經過測試發現在以上所說的隻是針對較低版本,我用的Android 2.3.3的版本對以上進行測試發現當在onCreate方法中調用 AnimationDrawable.start()方法時動畫會停留在第一幀,并沒有看到我們想要的效果。而當我把AnimationDrawable.start()方法放到onWindowFocusChanged 下時動畫是正常播放的,但是如果是運作在Android 4.1.2的模拟器上時會發現即使在onCreate方法中調用AnimationDrawable.start()方法動畫顯示也是正常的,是以為了安全起見我們最好将AnimationDrawable.start()方法放在onWindowFocusChanged 方法中。 (1)将動畫定義在XML中
下面我們就結合執行個體來做一個像下面的動畫
Android開發之Frame動畫(幀動畫)
首先在res下建立一個anim的檔案夾在此檔案夾下建立一個frame.xml檔案,frame.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/qb_tenpay_loading_1"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_2"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_3"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_4"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_5"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_6"  android:duration ="100" />  
    <item   android:drawable ="@drawable/qb_tenpay_loading_7"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_8"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_9"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_10"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_11"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_12"  android:duration ="100" />
</animation-list>
           
然後布局
<RelativeLayout
    xmlns:android= "http://schemas.android.com/apk/res/android"
    xmlns:tools= "http://schemas.android.com/tools"
    android:layout_width= "match_parent"
    android:layout_height= "match_parent"
    android:orientation= "horizontal"
    tools:context= ".MainActivity" >
    <Button
        android:id= "@+id/btn_play"
        android:layout_width= "wrap_content"
        android:layout_height= "wrap_content"
        android:text ="啟動動畫" />
    <Button
        android:id= "@+id/btn_stop"
        android:layout_width= "wrap_content"
        android:layout_height= "wrap_content"
        android:layout_toRightOf= "@id/btn_play"
        android:text ="停止動畫"/>
    <ImageView
        android:id= "@+id/iv_image"
        android:layout_width= "wrap_content"
        android:layout_height= "wrap_content"
        android:layout_centerInParent ="true"
        android:background= "@anim/frame" />
</RelativeLayout>
           
假如我們把AnimationDrawable.start()方法放在onCreate方法下如下
package com.example.animationpractice;

import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity {

     Button btnPlay;
     ImageView ivImage;
     Button btnStop;
      private AnimationDrawable anim;
     
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout. activity_main);
       
        btnPlay=(Button) findViewById(R.id. btn_play);
        ivImage=(ImageView) findViewById(R.id. iv_image);
        btnStop=(Button) findViewById(R.id. btn_stop);
       
        ivImage.setBackgroundResource(R.anim. frame);
        anim = (AnimationDrawable) ivImage.getBackground();
        anim.start();
     
        setClickListener();
    }

      private void setClickListener() {
            btnStop.setOnClickListener( new OnClickListener() {
                
                 @Override
                 public void onClick(View v) {
                      anim.stop();
                }
           });
       
        btnPlay.setOnClickListener( new OnClickListener() {
                
                 @Override
                 public void onClick(View v) {
                      anim.start();
                }
           });
     }
}
           
然後運作在Android 2.3.3的模拟器上發現次動畫隻停留在第一幀,但是當我們點選啟動動畫按鈕時動畫會正常的播放(因為此時windows視窗已經完全初始化),然後我們代碼不變将此工程運作在高版本上,我是運作在Android 4.1.2的模拟器上的,發現動畫是正常播放的(并沒有停留在第一幀)。但是為了相容性更好,更安全我們最好将啟動動畫的代碼寫在onWindowFocusChanged方法中,代碼如下
package com.example.animationpractice;

import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity {

     Button btnPlay;
     ImageView ivImage;
     Button btnStop;
     private AnimationDrawable anim;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout. activity_main);
      
        btnPlay=(Button) findViewById(R.id. btn_play);
        ivImage=(ImageView) findViewById(R.id. iv_image);
        btnStop=(Button) findViewById(R.id. btn_stop);
       
        setClickListener();
    }
     
      private void setClickListener() {
            btnStop.setOnClickListener( new OnClickListener() {
               
                 @Override
                 public void onClick(View v) {
                      //停止播放動畫
                     anim.stop();
                }
           });
      
        btnPlay.setOnClickListener( new OnClickListener() {
               
                 @Override
                 public void onClick(View v) {
                       //開始播放動畫
                      anim.start();
                }
         });
     }
    @Override
     public void onWindowFocusChanged( boolean hasFocus) {
     super.onWindowFocusChanged(hasFocus);
     //将背景設定為動畫
     ivImage.setBackgroundResource(R.anim. frame);
     anim = (AnimationDrawable) ivImage.getBackground();
     //啟動動畫
     anim.start();
   }
}
           
這樣無論在高版本還是低版本動畫的播放都是正常的。另外除了将
ivImage.setBackgroundResource(R.anim. frame);
 anim = (AnimationDrawable) ivImage.getBackground();
 anim.start();
           
這些代碼放在onWindowFocusChanged方法中之外還有一種解決方法通過開啟一個子線程的方式如
ivImage.post( new Runnable() { 
            @Override 
            public void run() { 
                 anim.start(); 
            } 
        });
           
此時工程的代碼如下
package com.example.animationpractice;

import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity {

     Button btnPlay;
     ImageView ivImage;
     Button btnStop;
      private AnimationDrawable anim;
     
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout. activity_main);
        btnPlay=(Button) findViewById(R.id. btn_play);
        ivImage=(ImageView) findViewById(R.id. iv_image);
        btnStop=(Button) findViewById(R.id. btn_stop);
       
       
        ivImage.setBackgroundResource(R.anim. frame);
        anim = (AnimationDrawable) ivImage.getBackground();
        ivImage.post( new Runnable() { 
            @Override 
            public void run() { 
                 anim.start(); 
            } 
        }); 
        setClickListener();
    }

      private void setClickListener() {
            btnStop.setOnClickListener( new OnClickListener() {
                
                 @Override
                 public void onClick(View v) {
                      anim.stop();
                }
           });
       
        btnPlay.setOnClickListener( new OnClickListener() {
                
                 @Override
                 public void onClick(View v) {
                      anim.start();
                }
           });
     }   
}
           

這種可以也可以同時在低和高版本中運作。

(2)完全由代碼實作動畫 完全通過代碼和定義在xml中是類似的隻不過将xml中的屬性或者标簽通過代碼的形式來定義

package com.example.animationpractice;

import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity {

     Button btnPlay;
     ImageView ivImage;
     Button btnStop;
      private AnimationDrawable anim;
     
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout. activity_main);
        ivImage=(ImageView) findViewById(R.id. iv_image);
       
        anim = new AnimationDrawable(); 
        for ( int i = 1; i <=12; i++) {
            //根據資源名稱和目錄擷取R.java中對應的資源ID 
            int id = getResources().getIdentifier("qb_tenpay_loading_" + i, "drawable" , getPackageName()); 
            //根據資源ID擷取到 Drawable對象 
            Drawable drawable = getResources().getDrawable(id); 
            //将此幀添加到AnimationDrawable中 
            anim.addFrame(drawable,100); 
        } 
        //設定循環播放
        anim.setOneShot( false); 
        //設定圖檔的背景為我們的動畫
        ivImage .setBackgroundDrawable (anim);
 
    }
   
    @Override
    public void onWindowFocusChanged( boolean hasFocus) {
      super.onWindowFocusChanged(hasFocus);
      //啟動動畫
      anim.start();
    }   
}
           

同樣我們需要注意将start()方法不要在視窗初始化的時候調用就行了。

源碼猛戳這裡

如有謬誤歡迎批評指正,如有疑問歡迎留言謝謝。