本文實例分析了Android動畫之逐幀動畫。分享給大家供大家參考,具體如下:
在開始實例講解之前,先引用官方文檔中的一段話:
Frame動畫是一系列圖片按照一定的順序展示的過程,和放電影的機制很相似,我們稱爲逐幀動畫。Frame動畫可以被定義在XML文件中,也可以完全編碼實現。
如果被定義在XML文件中,我們可以放置在/res下的anim或drawable目錄中(/res/[anim | drawable]/filename.xml),文件名可以作爲資源ID在代碼中引用;如果由完全由編碼實現,我們需要使用到AnimationDrawable對象。
如果是將動畫定義在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:onshot如果定義爲true的話,此動畫只會執行一次,如果爲false則一直循環。
<item>元素代表一幀動畫,android:drawable指定此幀動畫所對應的圖片資源,android:druation代表此幀持續的時間,整數,單位爲毫秒。
文檔接下來的示例我就不在解說了,因爲接下來我們也要結合自己的實例演示一下這個過程。
我們新建一個名爲anim的工程,將四張連續的圖片分別命名爲f1.png,f2.png,f3.png,f4.png,放於drawable目錄,然後新建一個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/f1" android:duration="300" />
<item android:drawable="@drawable/f2" android:duration="300" />
<item android:drawable="@drawable/f3" android:duration="300" />
<item android:drawable="@drawable/f4" android:duration="300" />
</animation-list>
我們可以將frame.xml文件放置於drawable或anim目錄,官方文檔上是放到了drawable中了,大家可以根據喜好來放置,放在這兩個目錄都是可以運行的。
然後介紹一下佈局文件res/layout/frame.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:id="@+id/frame_image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="stopFrame"
android:onClick="stopFrame"/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="runFrame"
android:onClick="runFrame"/>
</LinearLayout>
我們定義了一個ImageView作爲動畫的載體,然後定義了兩個按鈕,分別是停止和啓動動畫。
接下來介紹一下如何通過加載動畫定義文件來實現動畫的效果。我們首先會這樣寫:
package com.scott.anim;
import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
public class FrameActivity extends Activity {
private ImageView image;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.frame);
image = (ImageView) findViewById(R.id.frame_image);
image.setBackgroundResource(R.anim.frame);
AnimationDrawable anim = (AnimationDrawable) image.getBackground();
anim.start();
}
}
看似十分完美,跟官方文檔上寫的一樣,然而當我們運行這個程序時會發現,它只停留在第一幀,並沒有出現我們期望的動畫,也許你會失望的說一句:“Why?”,然後你把相應的代碼放在一個按鈕的點擊事件中,動畫就順利執行了,再移回到onCreate中,還是沒效果,這個時候估計你會氣急敗壞的吼一句:“What the fuck!”。但是,什麼原因呢?如何解決呢?
出現這種現象是因爲當我們在onCreate中調用AnimationDrawable的start方法時,窗口Window對象還沒有完全初始化,AnimationDrawable不能完全追加到窗口Window對象中,那麼該怎麼辦呢?我們需要把這段代碼放在onWindowFocusChanged方法中,當Activity展示給用戶時,onWindowFocusChanged方法就會被調用,我們正是在這個時候實現我們的動畫效果。當然,onWindowFocusChanged是在onCreate之後被調用的,如圖:
然後我們需要重寫一下代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package
com.scott.anim; import
android.app.Activity; import
android.graphics.drawable.AnimationDrawable; import
android.graphics.drawable.Drawable; import
android.os.Bundle; import
android.view.View; import
android.widget.ImageView; public
class FrameActivity extends
Activity { private
ImageView image; @Override protected
void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.frame); image = (ImageView) findViewById(R.id.frame_image); } @Override public
void onWindowFocusChanged( boolean
hasFocus) { super .onWindowFocusChanged(hasFocus); image.setBackgroundResource(R.anim.frame); AnimationDrawable anim = (AnimationDrawable) image.getBackground(); anim.start(); } } |
運行一下,動畫就可以正常顯示了。
如果在有些場合,我們需要用純代碼方式實現一個動畫,我們可以這樣寫:
AnimationDrawable anim = new AnimationDrawable();
for (int i = 1; i <= 4; i++) {
int id = getResources().getIdentifier("f" + i, "drawable", getPackageName());
Drawable drawable = getResources().getDrawable(id);
anim.addFrame(drawable, 300);
}
anim.setOneShot(false);
image.setBackgroundDrawable(anim);
anim.start();
完整的FrameActivity.java代碼如下:
package com.scott.anim;
import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
public class FrameActivity extends Activity {
private ImageView image;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.frame);
image = (ImageView) findViewById(R.id.frame_image);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
image.setBackgroundResource(R.anim.frame); //將動畫資源文件設置爲ImageView的背景
AnimationDrawable anim = (AnimationDrawable) image.getBackground(); //獲取ImageView背景,此時已被編譯成AnimationDrawable
anim.start(); //開始動畫
}
public void stopFrame(View view) {
AnimationDrawable anim = (AnimationDrawable) image.getBackground();
if (anim.isRunning()) { //如果正在運行,就停止
anim.stop();
}
}
public void runFrame(View view) {
//完全編碼實現的動畫效果
AnimationDrawable anim = new AnimationDrawable();
for (int i = 1; i <= 4; i++) {
//根據資源名稱和目錄獲取R.java中對應的資源ID
int id = getResources().getIdentifier("f" + i, "drawable", getPackageName());
//根據資源ID獲取到Drawable對象
Drawable drawable = getResources().getDrawable(id);
//將此幀添加到AnimationDrawable中
anim.addFrame(drawable, 300);
}
anim.setOneShot(false); //設置爲loop
image.setBackgroundDrawable(anim); //將動畫設置爲ImageView背景
anim.start(); //開始動畫
}
}
|