1. 程式人生 > >2014-10-31Android學習------序列幀動畫,開始,結束監聽的解決--------GIF動畫實現

2014-10-31Android學習------序列幀動畫,開始,結束監聽的解決--------GIF動畫實現

寫一篇文章很辛苦啊!!!

轉載請註明,聯絡請郵件[email protected]

我學習Android都是結合原始碼去學習,這樣比較直觀,非常清楚的看清效果,覺得很好,今天的學習原始碼是網上找的個AnimationTest 原始碼 百度搜就知道很多下載的地方  網上原始碼的名字叫:序列幀動畫,開始,結束監聽的解決.zip

監聽事件非常的常見  也經常用   我們一般都是利用系統裡面的方法去實現    

監聽事件可以是觸控(一般是按下,拖動,鬆開)  可以是點選(點選事件是指你設定了一個按鈕或者圖片等)

但是當你自己去定義一個View的時候,這個時候介面就需要你自己去定義了  

系統自定義定義的widget都是有相應的監聽事件的處理,但是你自己定義了一個widget  就需要去自己寫出來了,

這節將的就是當我們繼承View實現了動畫的展示,但是我們需要去監聽這個動畫並有操作該怎麼辦?該怎麼去寫這樣的函式

其實它的原理跟前面的文章:26個字母的列表實現是一樣的 點選我檢視

根據前面的例子我們知道一般步驟是這樣的:

1.自己定義一個類  讓它繼承Android.view.View   

2.過載這個類的建構函式,然後處理OnDraw()函式  

3.如果我們想要自己定義的檢視能夠被監聽,是需要再類中新增監聽介面(定義方法不實現)

4.如果想要這個自定義的檢視實現監聽,在activity中,那麼首先需要把它  放在  佈局檔案中,也就是你需要在layout中有定義

做法一般是這樣的:

<com.wust.citylist.activity.MyLetterListView  
    android:id="@+id/cityLetterListView"  
    android:layout_width="30dip"  
    android:layout_height="fill_parent"  
    android:layout_alignParentRight="true"  
    android:background="#40000000" />  
  看到沒有  我們只關心 這句話:com.wust.citylist.activity.MyLetterListView

這樣做就把我們自己定義的檢視當做一個控制元件顯示在佈局上了,這個時候我們就可以去處理它的監聽事件了

5.接下來就在實現這個佈局檔案的activity類中去實現這個介面中的函式就可以了  也就是過載  

上面的步驟應該說的夠清楚了,接下來我們就來看看  幀動畫事件的監聽處理

一. 定義自己的檢視

import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.os.Handler;
import android.util.AttributeSet;
import android.widget.ImageView;

public class AnimationImageView extends ImageView {

	public AnimationImageView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	public AnimationImageView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
	}

	public AnimationImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	public interface OnFrameAnimationListener{
		/**
		 * 動畫開始播放後呼叫
		 */
		void onStart();
		/**
		 * 動畫結束播放後呼叫
		 */
		void onEnd();
	}
	
	/**
	 * 不帶動畫監聽的播放
	 * @param resId
	 */
	public void loadAnimation(int resId){
		setImageResource(resId);
		AnimationDrawable anim = (AnimationDrawable)getDrawable();
		anim.start();
	}
	
	/**
	 * 帶動畫監聽的播放
	 * @param resId
	 * @param listener
	 */
	public void loadAnimation(int resId, final OnFrameAnimationListener listener) {
		setImageResource(resId);
		AnimationDrawable anim = (AnimationDrawable)getDrawable();
		anim.start();
		if(listener != null){
			// 呼叫回撥函式onStart
			listener.onStart();
		}
		
		// 計算動態圖片所花費的事件
		int durationTime = 0;
        for (int i = 0; i < anim.getNumberOfFrames(); i++) {
            durationTime += anim.getDuration(i);
        }
        
        // 動畫結束後
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
			
			@Override
			public void run() {
				if(listener != null){
					// 呼叫回撥函式onEnd
					listener.onEnd();
				}
			}
		}, durationTime);
	}
	
}

code說明:

1.第一個這個類是繼承ImageView  ,上篇文章我們是直接繼承View的


2.建構函式 處理 這裡不需要我們關係:右鍵 source  ->generate constructors from superclass....  然後全部勾選就可以了

3.監聽事件的介面:

public interface OnFrameAnimationListener{
/**
* 動畫開始播放後呼叫
*/
void onStart();
/**
* 動畫結束播放後呼叫
*/
void onEnd();
}

這個就是像我們的生命週期一樣,當建立之後可以做哪些操作,結束之後有可以做哪些操作,至於怎麼操作需要你自己再去重寫

4.當這些做完了,我們就需要把動畫載入到檢視上去了,而載入到檢視上是怎麼實現的呢?

它是先從檔案中把圖片載入到動畫這個類上,然後再有這個類放在檢視上,就想上篇文章,我們定義一個Movie類一樣,不過這裡是 AnimationDrawable,

首先我們來看看官方API是怎麼樣介紹的:

Class Overview

An object used to create frame-by-frame animations, defined by a series of Drawable objects, which can be used as a View object's background.

The simplest way to create a frame-by-frame animation is to define the animation in an XML file, placed in the res/drawable/ folder, and set it as the background to a View object. Then, call run() to start the animation.

An AnimationDrawable defined in XML consists of a single <animation-list> element, and a series of nested <item> tags. Each item defines a frame of the animation.

我們只看類概述:

該物件是用來建立序列幀動畫的(一幀接一幀動畫),這些系列幀動畫是通過一系列可以繪製的物件來定義的,

而這些可以繪製的物件能夠被作為一個View物件的背景。

建立系列幀動畫最簡單的方法就是在XML檔案中去定義動畫,把它們放在資料夾下,res/drawable/folder(folder是可以自己定義的,也可以不要這個檔案),把他們設定為一個檢視物件的背景。然後,呼叫函式run()去啟動動畫

一個AnimationDrawable(可繪製動畫) 是在XML中定義的,它通常是這樣定義的(由下面的這些組成):在xml檔案中

根節點是<animation-list>,子節點是<item>,每一個<item>定義動畫的的一幀(也就是一幀動畫)

看看官方給出的例子:

See the example below.

spin_animation.xml file in res/drawable/ folder:

<!-- Animation frames are wheel0.png -- wheel5.png files inside the
 res/drawable/ folder --><animation-listandroid:id="selected"android:oneshot="false"><itemandroid:drawable="@drawable/wheel0"android:duration="50"/><itemandroid:drawable="@drawable/wheel1"android:duration="50"/><itemandroid:drawable="@drawable/wheel2"android:duration="50"/><itemandroid:drawable="@drawable/wheel3"android:duration="50"/><itemandroid:drawable="@drawable/wheel4"android:duration="50"/><itemandroid:drawable="@drawable/wheel5"android:duration="50"/></animation-list>

Here is the code to load and play this animation.

// Load the ImageView that will host the animation and// set its background to our AnimationDrawable XML resource.ImageView img =(ImageView)findViewById(R.id.spinning_wheel_image);
 img.setBackgroundResource(R.drawable.spin_animation);// Get the background, which has been compiled to an AnimationDrawable object.AnimationDrawable frameAnimation =(AnimationDrawable) img.getBackground();// Start the animation (looped playback by default).
 frameAnimation.start()
注意到:
// Get the background, which has been compiled to an AnimationDrawable object.AnimationDrawable frameAnimation =(AnimationDrawable) img.getBackground();
()Return the view's drawable, or null if no drawable has been assigned.
getBackground()和getDrawable有什麼區別呢?你可以它的解釋, // 得到背景,這個背景已經被編譯成為一個AnimationDrawable物件 這個是一個繼承的方法。 但是兩個人返回的物件是一樣的。我們看上面的類介紹可以看到    AnimationDrawable是繼承Drawable類的: 通過API的學習我們知道了要想利用這個AnimationDrawable我們必須先去定義一些XML檔案,每一個xml檔案描述的就是動畫要顯示的內容,該動畫的每一幀動畫內容是有<item>來定義的,以及顯示的時長,既然這樣,我們就必須先去了解這樣的xml檔案有哪些屬性是可以設定的呢? 再看看官方的API:
XML Attributes
Attribute Name Related Method Description
Reference to a drawable resource to use for the frame. 
Amount of time (in milliseconds) to display this frame. 
If true, the animation will only run a single time and then stop. 
If true, allows the drawable's padding to change based on the current state that is selected. 
Provides initial visibility state of the drawable; the default value is false. 
我們要關係的就是三個屬性: 1.android:drawable  :引用一個可以繪製的資源來描述該幀  它是定義在item中的 2.android:duration   :動畫的時間長度,以毫秒為單位,來顯示該幀,  它是定義在item中的 3.android:oneshot   :如果為true,那麼該動畫將執行執行一次,然後停止  它是定義在<animation-list>中的 瞭解了這些,我們接下來就需要去寫自己的動畫了,使用XML:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true" >

    <item
        android:drawable="@drawable/besg00042"
        android:duration="150">
    </item>
    <item
        android:drawable="@drawable/besg00041"
        android:duration="150">
    </item>

</animation-list>

這樣做了之後,我們再回來這個函式的處理: 看下面的函式 public void loadAnimation(int resId){// 引數resID是資原始檔對應的id setImageResource(resId);//用這個id對應的檔案來佈置ImageView檢視的內容,也就是當前我們繼承的AnimationView類, AnimationDrawable anim = (AnimationDrawable)getDrawable();//得到一個AnimationDrawable物件 anim.start();//然後啟動動畫 } 上面的函式就是上面的,如果沒有監聽事件,就這樣寫,但是如果有監聽事件的話,我們是怎麼讓這些動畫載入到檢視上去的呢? 我們繼續往下分析: /**
* 帶動畫監聽的播放
* @param resId
* @param listener  注意到這裡一個final來修飾這個引數,因為我們的介面是內部定義的,如果不這樣
 *  定義是會出錯的。
*/
public void loadAnimation(int resId, final OnFrameAnimationListener listener) {
setImageResource(resId);
AnimationDrawable anim = (AnimationDrawable)getDrawable();
anim.start();
//到這裡為止,思路跟沒有監聽的思路是一致的,那麼有了監聽事件就繼續往下走
if(listener != null){//如果有監聽事件的話,那麼馬上去呼叫監聽事件的處理函式,也就是監聽被
//觸發了
// 呼叫回撥函式onStart
listener.onStart();//這個函式是介面中定義但沒有被實現的方法,到底要執行什麼,需要去
//activity類中去過載它
}

// 計算動態圖片所花費的時間
int durationTime = 0;
      for (int i = 0; i < anim.getNumberOfFrames(); i++) {
           durationTime += anim.getDuration(i);
       }
        
        // 動畫結束後
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {

@Override
public void run() {
if(listener != null){
// 呼叫回撥函式onEnd
listener.onEnd();
}
}
}, durationTime);
}

public int getDuration (int i)

Returns
  • The duration in milliseconds of the frame at the specified index
返回值:指定的幀動畫的時間

public int getNumberOfFrames ()

Returns
  • The number of frames in the animation
返回值:動畫的幀數(也就是一個xml檔案對應有多少幀(item的個數)) 到這裡為止,這個類的作用和函式我們都基本掌握了,接下來就是如何在activity中去實現它呢? 二。按照上面的步驟,當這個自定義的檢視View物件定義好之後,想要在activity中處理它的監聽事件,必須把它放到佈局檔案中去,那麼我們就在佈局檔案中去定義它     <com.wust.animationtest.ui.AnimationImageView
        android:id="@+id/anim_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
三。當在main.xml定義好之後,我們需要去處理activity類了: 1.在onCreate(Bundle )類中先去載入這個佈局 @Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);//載入佈局
initView();//初始化    這裡主要是找到佈局檔案中的各個控制元件
setListener();//設定監聽事件 這種寫法就是讓當前的類去實現implements OnClickListener
}
private void initView() {
// TODO Auto-generated method stub
anim_view = (AnimationImageView) findViewById(R.id.anim_view);//找到這個控制元件
attack = (Button) this.findViewById(R.id.attack);
defense = (Button) this.findViewById(R.id.defense);
// 載入預設的動態圖
anim_view.loadAnimation(R.drawable.anim_idle);首先是讓當前的檢視就有動畫,初始化動畫
}
private void setListener() {
// TODO Auto-generated method stub
attack.setOnClickListener(this);
defense.setOnClickListener(this);
}
接下來就是用按鈕的點選事件來實現對動畫的監聽: @Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.attack:
// 如果點選了該按鈕,載入帶監聽的動態圖  播放攻擊動作  
// 注意到這個引數,是一個內部類的形式
anim_view.loadAnimation(R.drawable.anim_attack,
new OnFrameAnimationListener() {

@Override
public void onStart() {
// 動畫剛播放時
// 可以載入你自己的程式碼,也即是使用者點選了攻擊按鈕,你想幹什麼
}
@Override
public void onEnd() {
// 動畫結束播放時
// 還原回預設動態圖  讓檢視的背景重新返回初始化時設定的樣子
anim_view.loadAnimation(R.drawable.anim_idle);
}
});
break;
case R.id.defense:
// 載入帶監聽的動態圖 防禦動作
anim_view.loadAnimation(R.drawable.anim_defense,
new OnFrameAnimationListener() {
@Override
public void onStart() {
// 動畫剛播放時
}
@Override
public void onEnd() {
// 動畫結束播放時

// 還原回預設動態圖
anim_view.loadAnimation(R.drawable.anim_idle);
}
});
break;
}

}
至此activity也就完成了,接下來去配置下清單檔案就可以部署了, 我們看看效果圖:
關於動畫還有其他的方式,這裡就先不講了,下次有機會再學習。

相關推薦

2014-10-31Android學習------序列動畫,開始,結束解決--------GIF動畫實現

寫一篇文章很辛苦啊!!! 轉載請註明,聯絡請郵件[email protected] 我學習Android都是結合原始碼去學習,這樣比較直觀,非常清楚的看清效果,覺得很好,今天的學習原始碼是網上找的個AnimationTest 原始碼 百度搜就知道很多下載的

2014-10-27Android學習------SQLite資料庫操作(二)-----資料庫的建立--SQLiteHelper extends SQLiteOpenHelper

上篇有篇文章講了資料庫的操作  條件是:資料庫已經建好的了,我們只需要從裡面獲取資料(查詢)就可以了, 現在我們來看看第二種資料庫的操作: class SQLiteHelper extends SQLiteOpenHelper 封裝一個繼承SQLiteOpenHelpe

Android學習之自定義TextWatcher來文字最大輸入字數

開發中有種很可能會遇到的需求就是限制EditText的文字輸入字數,例如微博就限制140字,如果只是限制輸入的字數的話很簡單,EditText有個屬性叫android:maxLength,設定140就

學習筆記】Bootstrap外掛 滾動+彈出框+選項卡

--滾動監聽 依賴導航元件步驟:1.寫一個導航元件2.data-target="#test"執行滾動監聽的目標   data-spy="scroll" 向想要監聽的元素 新增滾動監聽 <nav id="test" class="navbar navbar-defa

js配合錨點實現動畫滾動與

這個技能感覺不錯,配合bootstrap寫出的。下面是乾貨: ul 的每個li的每個a中的href指向錨點目標,比如說<li class="active"><a href="#index">Home</a></li&g

特效序列動畫,可指定開始結束

 直接貼程式碼: Shader "James/FX/MeshFrame" { Properties { [Enum(Add, 1, Blend, 10)] _DstBlend ("Blend Mode", Float) = 1 _Ma

關於在unity中使用序列動畫

atime highlight ++ switch ati 是你 一秒 tor 報錯 //動畫數組 public object[] anim; //限制一秒多少幀 public float fps = 30; //幀序列 priv

Html5 序列動畫

下一個 XML default idt 毫秒 meta document etc array <!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <he

從零開始學習前端開發 — 15、CSS3變形基礎過渡、動畫

steps 方式 css3動畫 rec step round 保持 start radius 一、css3過渡 語法: transition: 過渡屬性 過渡時間 延遲時間 過渡方式; 1.過渡屬性(transition-property) 取值:all 所有發生變化的cs

UV序列動畫

sub sam ble parent image png ons custom 分享圖片 通過上圖實現一個火焰的序列幀動畫(使用UV實現美術只需要出一張圖,而不用每個火焰狀態出一張圖,節省了內存)。 shader如下: Shader "Custom/UVAnimatio

Cocos2d-x 3.x序列動畫

vector 序列幀 bash cpp ams with 序列 object -s Animation : 一個給精靈對象執行的幀動畫對象。 Animate:是將動畫包裝成動作的類。 AnimationCache:管理動畫的單例。 簡介 Animat

學習筆記:從0開始學習大資料-10. hive安裝部署

1. 下載 wget http://archive.cloudera.com/cdh5/cdh/5/hive-1.1.0-cdh5.15.1.tar.gz 2.解壓 tar -zxvf hive-1.1.0-cdh5.15.1.tar.gz 3.  hive的元資料(如表名,列

WPF 序列動畫

直接上程式碼 private void LoadPics() { try { _storyboard = new Storyboard(); for (int i =

2014.10】神經網路中的深度學習綜述

本綜述的主要內容包括: 神經網路中的深度學習簡介 神經網路中面向事件的啟用擴充套件表示法 信貸分配路徑(CAPs)的深度及其相關問題 深度學習的研究主題 有監督神經網路/來自無監督神經網路的幫助 FNN與RNN中用於強化學習RL

css精靈圖寫序列動畫

     最近寫一個H5要求序列幀動畫比較多,但是卻僅僅是作為裝飾,而不對其進行操作,為了減小記憶體以及更好的效能選擇了css動畫+css精靈圖的方式。 1.找工具製作css精靈圖。     聽說Win系統的css sprite很好用,可惜m

楓葉天空Cocos2d-x3.0系列教程二 序列動畫

更新日誌: 2014-01-31  增加了cocoStudio動畫編輯器的說明 內容概述: 從今天開始,我們就正式進入cocos2d-x3.0的開發教程了,本篇的核心內容是序列幀動畫。 準備工作 1、首先我們建立一個新的場景類,作為我們本系列教程的一

Cocos2d-序列動畫

基礎原理 Cocos2d-x中,動畫的具體內容是依靠精靈顯示出來的,為了顯示動態圖片,我們需要不停切換精靈顯示的內容,通過把靜態的精靈變為動畫播放器從而實現動畫效果。動畫由幀組成,每一幀都是一個紋理,我們可以使用一個紋理序列來建立動畫。 我們使用Animat

Unity3D學習筆記(10)—— 遊戲序列

        這期內容有關遊戲的序列化,什麼是序列化呢?額...就是遊戲的內容可以輸出成文字格式,或者遊戲的內容可以從文字中解析獲得。現在的遊戲幾乎離不開序列化,只要有存檔機制的遊戲必然會序列化,並且遊戲的每次啟動都會讀取序列文字。另外遊戲的更新也和序列化緊密相關,比如L

AM335x(TQ335x)學習筆記——u-boot-2014.10移植

最近移植了下u-boot-2014.10到TQ335x,如果基於am335x evm進行移植,需要修改的地方並不多。 由於TI的am335x evm開發使用了一個eeprom儲存了板載配置資訊,用來區分不同板子的型號的,而TQ335x沒有這個eeprom,因此,需要修改ee

關於cocos2d序列動畫plist檔案的建立

轉載請註明出處 用過的人都知道,cocos2d的動畫編輯器是多麼的坑,自從cocos2d支援Animation後,開始使用Animation動畫了。關於Animation的使用網上也有很多,但是我看了一下,主流的就是兩種方法,一是:手動新增,將plist檔案裡的精靈幀一