生活随笔
收集整理的這篇文章主要介紹了
八、图形与图像处理(2)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
8、逐幀(Frame)動(dòng)畫
要求開(kāi)發(fā)者把動(dòng)畫過(guò)程的沒(méi)漲靜態(tài)圖片都收集起來(lái),然后由Android開(kāi)控制依次顯示這些靜態(tài)圖片,與放電影的原理一樣。
9、AnimationDrawable與逐幀動(dòng)畫
只要在<animation-list.../>元素中使用<item.../>子元素定義動(dòng)畫的全部幀,并指定各幀的持續(xù)時(shí)間即可。語(yǔ)法格式如下:
<?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>
android:oneshot控制該動(dòng)畫是否循環(huán)播放(true:不會(huì)循環(huán)播放)。每個(gè)<item/>子元素添加一幀。
【提示】Android完全支持在Java代碼中創(chuàng)建逐幀動(dòng)畫,如果開(kāi)發(fā)者喜歡的話,完全可以先創(chuàng)建AnimationDrawable對(duì)象,
然后調(diào)用addFrame(Drawable frame, int duration)向該動(dòng)畫中添加幀,每調(diào)用一次addFrame方法,就像<animation-list.../>
元素中添加一個(gè)<item.../>子元素。
一旦程序獲取了AnimationDrawable對(duì)象之后,接下來(lái)就可用ImageView把AnimationDrawable顯示出來(lái)---習(xí)慣上把AnimationDrawable
設(shè)置成ImageView的背景即可。
范例:功夫熊貓動(dòng)畫。
1 <?xml version="1.0" encoding="utf-8"?>
2 <!-- 指定動(dòng)畫循環(huán)播放 fat_po.xml -->
3 <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
4 android:oneshot="false">
5 <!-- 添加多個(gè)幀 -->
6 <item android:drawable="@drawable/fat_po_f01" android:duration="60" />
7 <item android:drawable="@drawable/fat_po_f02" android:duration="60" />
8 <item android:drawable="@drawable/fat_po_f03" android:duration="60" />
9 <item android:drawable="@drawable/fat_po_f26" android:duration="60" />
10 <item android:drawable="@drawable/fat_po_f27" android:duration="60" />
11 </animation-list> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:background="#fff"android:orientation="vertical" ><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:gravity="center"android:orientation="horizontal" ><Buttonandroid:id="@+id/play"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/play" /><Buttonandroid:id="@+id/stop"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/stop" /></LinearLayout><ImageViewandroid:id="@+id/anim"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@anim/fat_po"android:scaleType="center" />
</LinearLayout> 1 // 獲取AnimationDrawable動(dòng)畫對(duì)象,并設(shè)置到ImageView背景上。
2 final AnimationDrawable anim = (AnimationDrawable) imageView
3 .getBackground();
4 play.setOnClickListener(new OnClickListener() {
5 @Override
6 public void onClick(View v) {
7 // 開(kāi)始播放動(dòng)畫
8 anim.start();
9 }
10 });
11 stop.setOnClickListener(new OnClickListener() {
12 @Override
13 public void onClick(View v) {
14 // 停止播放動(dòng)畫
15 anim.stop();
16 }
17 }); 【注意】AnimationDrawable代表的動(dòng)畫默認(rèn)是不播放的,必須在程序中啟動(dòng)動(dòng)畫播放才可以。
AnimationDrawable提供了如下兩個(gè)方法來(lái)開(kāi)始、停止動(dòng)畫。
start():開(kāi)始播放動(dòng)畫。
stop():停止播放動(dòng)畫。
范例:在指定點(diǎn)爆炸
爆炸效果實(shí)際上是一個(gè)逐幀動(dòng)畫,開(kāi)發(fā)者需要收集從開(kāi)始爆炸到爆炸結(jié)束的所有靜態(tài)圖片,再
將這些圖片定義成一個(gè)逐幀動(dòng)畫,接著在碰撞點(diǎn)播放該逐幀動(dòng)畫即可。
<!-- res\anim\blast.xml -->
<?xml version="1.0" encoding="utf-8"?>
<!-- 定義動(dòng)畫只播放一次,不循環(huán) -->
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"android:oneshot="true" ><item android:drawable="@drawable/bom_f01" android:duration="80" /><item android:drawable="@drawable/bom_f02" android:duration="80" /><item android:drawable="@drawable/bom_f03" android:duration="80" /><item android:drawable="@drawable/bom_f26" android:duration="80" /><item android:drawable="@drawable/bom_f27" android:duration="80" />
</animation-list> public class Blast extends Activity {private MyView myView;private AnimationDrawable anim;private MediaPlayer bomb;public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 使用FrameLayout布局管理器,它允許組件自己控制位置FrameLayout frame = new FrameLayout(this);setContentView(frame);// 設(shè)置使用背景
frame.setBackgroundResource(R.drawable.back);// 加載音效bomb = MediaPlayer.create(this, R.raw.bomb);myView = new MyView(this);// 設(shè)置myView用于顯示blast動(dòng)畫
myView.setBackgroundResource(R.anim.blast);// 設(shè)置myView默認(rèn)為隱藏
myView.setVisibility(View.INVISIBLE);// 獲取動(dòng)畫對(duì)象anim = (AnimationDrawable) myView.getBackground();frame.addView(myView);frame.setOnTouchListener(new OnTouchListener() {@Overridepublic boolean onTouch(View source, MotionEvent event) {// 只處理按下事件(避免每次產(chǎn)生兩個(gè)動(dòng)畫效果)if (event.getAction() == MotionEvent.ACTION_DOWN) {// 先停止動(dòng)畫播放
anim.stop();float x = event.getX();float y = event.getY();// 控制myView的顯示位置myView.setLocation((int) y - 40, (int) x - 20);myView.setVisibility(View.VISIBLE);// 啟動(dòng)動(dòng)畫
anim.start();// 播放音效
bomb.start();}return false;}});}// 定義一個(gè)自定義View,該自定義View用于播放“爆炸”效果class MyView extends ImageView {public MyView(Context context) {super(context);}// 定義一個(gè)方法,該方法用于控制MyView的顯示位置public void setLocation(int top, int left) {this.setFrame(left, top, left + 40, top + 40);}// 重寫該方法,控制如果動(dòng)畫播放到最后一幀時(shí),隱藏該View
@Overrideprotected void onDraw(Canvas canvas) {try {Field field = AnimationDrawable.class.getDeclaredField("mCurFrame");field.setAccessible(true);// 獲取anim動(dòng)畫的當(dāng)前幀int curFrame = field.getInt(anim);// 如果已經(jīng)到了最后一幀if (curFrame == anim.getNumberOfFrames() - 1) {// 讓該View隱藏
setVisibility(View.INVISIBLE);}} catch (Exception e) {}super.onDraw(canvas);}}
} 10、補(bǔ)間(Tween)動(dòng)畫
補(bǔ)間動(dòng)畫就是指開(kāi)發(fā)者只需指定動(dòng)畫開(kāi)始、動(dòng)畫結(jié)束“關(guān)鍵幀”,而動(dòng)畫變化的“中間幀”由系統(tǒng)計(jì)算并補(bǔ)齊,
這就是把Tween動(dòng)畫翻譯為“補(bǔ)間動(dòng)畫”的原因。
11、Tween動(dòng)畫與Interpolator
? ? ?對(duì)于補(bǔ)間動(dòng)畫而言,開(kāi)發(fā)者無(wú)需"逐一"定義動(dòng)畫過(guò)程中的每一幀。只要定義動(dòng)畫開(kāi)始、結(jié)束的關(guān)鍵幀,并指定動(dòng)畫的持續(xù)時(shí)間即可。
?
Interpolator根據(jù)特定算法計(jì)算出整個(gè)動(dòng)畫所需要?jiǎng)討B(tài)插入幀的密度和位置,簡(jiǎn)單說(shuō),
Interpolator負(fù)責(zé)控制動(dòng)畫的變化速度,這就使得基本的動(dòng)畫效果(Alpha、Scale、Translate、Rotate)
能以勻速變化、加速、減速、拋物線速度等各種速度變化。
Interpolator是一個(gè)接口,它定義了所有Interpolator都需要實(shí)現(xiàn)的方法:float getInterpolation(float input),
開(kāi)發(fā)者完全可以通過(guò)實(shí)現(xiàn)Interpolator來(lái)控制動(dòng)畫的變化速度。
Android為Interpolator提供了如下幾個(gè)實(shí)現(xiàn)類:分別用于實(shí)現(xiàn)不同動(dòng)畫變化速度。
● LinearInterpolator:動(dòng)畫以均勻的速度改變。
● AccelerateInterpolator:在動(dòng)畫開(kāi)始的地方改變速度較慢,然后開(kāi)始加速。
● AccelerateDecelerateInterpolator:在動(dòng)畫開(kāi)始、結(jié)束的地方改變速度較慢,在中間的時(shí)候加速。
● CycleInterpolator:運(yùn)動(dòng)循環(huán)播放特定的次數(shù),變化速度按正玄曲線改變。
● DecelerateInterpolator:在動(dòng)畫開(kāi)始的地方改變速度較快,然后開(kāi)始減慢。
為了實(shí)現(xiàn)動(dòng)畫資源文件中指定補(bǔ)間動(dòng)畫所使用的Interpolator,定義補(bǔ)間動(dòng)畫的<set.../>元素支持一個(gè)
android:interpolator屬性,該屬性的屬性值可以指定為Android默認(rèn)支持的Interpolator。
● @android:anim/linear_interpolator
● @android:anim/accelerate_interpolator
● @android:anim/accelerate_decelerate_interpolator
......
其實(shí)上面的寫法很有規(guī)律,它們就是把系統(tǒng)提供的Interpolator實(shí)現(xiàn)類的類名的駝峰寫法改為
中劃線寫法即可。
一旦在程序中通過(guò)AnimationUtils得到代表補(bǔ)間動(dòng)畫的Animation之后,接下來(lái)就可調(diào)用View
的startAnimation(Animation anim)方法開(kāi)始對(duì)該View執(zhí)行動(dòng)畫了。
12、位置、大小、旋轉(zhuǎn)度、透明度改變的補(bǔ)間動(dòng)畫
雖然Android允許在程序中創(chuàng)建Animation對(duì)象,但實(shí)際上一般都會(huì)采用動(dòng)畫資源文件來(lái)定義補(bǔ)間動(dòng)畫。
實(shí)例:介紹補(bǔ)間動(dòng)畫(包括兩個(gè)動(dòng)畫資源文件)
第一個(gè)動(dòng)畫資源文件控制圖片以旋轉(zhuǎn)的方式縮小,該動(dòng)畫資源文件如下:
<!-- res\anim\anim.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<!-- 指定動(dòng)畫勻速改變 -->
<set xmlns:android="http://schemas.android.com/apk/res/android"android:interpolator="@android:anim/linear_interpolator"><!-- 定義縮放變換 --><scale android:fromXScale="1.0" android:toXScale="0.01" android:fromYScale="1.0" android:toYScale="0.01" android:pivotX="50%" android:pivotY="50%" android:fillAfter="true" android:duration="3000"/> <!-- 定義透明度的變換 --><alpha android:fromAlpha="1" android:toAlpha="0.05" android:duration="3000"/> <!-- 定義旋轉(zhuǎn)變換 --><rotate android:fromDegrees="0" android:toDegrees="1800" android:pivotX="50%" android:pivotY="50%" android:duration="3000"/>
</set> 上面的動(dòng)畫資源指定動(dòng)畫勻速變化,同時(shí)進(jìn)行縮放、透明度改變、旋轉(zhuǎn)三種改變,動(dòng)畫持續(xù)時(shí)間為三秒。
第二個(gè)動(dòng)畫資源則控制圖片以動(dòng)畫的方式恢復(fù)回來(lái),對(duì)應(yīng)的動(dòng)畫資源如下:\res\anim\reverse.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 指定動(dòng)畫勻速改變 -->
<set xmlns:android="http://schemas.android.com/apk/res/android"android:interpolator="@android:anim/linear_interpolator"android:startOffset="3000"><!-- 定義縮放變換 --><scale android:fromXScale="0.01" android:toXScale="1" android:fromYScale="0.01" android:toYScale="1" android:pivotX="50%" android:pivotY="50%" android:fillAfter="true" android:duration="3000"/> <!-- 定義透明度的變換 --><alpha android:fromAlpha="0.05" android:toAlpha="1" android:duration="3000"/> <!-- 定義旋轉(zhuǎn)變換 --><rotate android:fromDegrees="1800" android:toDegrees="0" android:pivotX="50%" android:pivotY="50%" android:duration="3000"/>
</set> 定義動(dòng)畫資源之后,接下來(lái)就可以利用AnimationUtils工具類來(lái)加載指定的動(dòng)畫資源,加載成功后會(huì)返回一個(gè)Animation,
該對(duì)象即可控制圖片或視圖播放動(dòng)畫。
public class TweenAnim extends Activity {@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);final ImageView flower = (ImageView) findViewById(R.id.flower);// 加載第一份動(dòng)畫資源final Animation anim = AnimationUtils.loadAnimation(this, R.anim.anim);// 設(shè)置動(dòng)畫結(jié)束后保留結(jié)束狀態(tài)anim.setFillAfter(true);// 加載第二份動(dòng)畫資源final Animation reverse = AnimationUtils.loadAnimation(this,R.anim.reverse);// 設(shè)置動(dòng)畫結(jié)束后保留結(jié)束狀態(tài)reverse.setFillAfter(true);Button bn = (Button) findViewById(R.id.bn);final Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {if (msg.what == 0x123) {flower.startAnimation(reverse);}}};bn.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View arg0) {flower.startAnimation(anim);// 設(shè)置3.5秒后啟動(dòng)第二個(gè)動(dòng)畫new Timer().schedule(new TimerTask() {@Overridepublic void run() {handler.sendEmptyMessage(0x123);}}, 3500);}});}
} 范例:蝴蝶飛舞
蝴蝶飛行時(shí)的振翅效果是逐幀動(dòng)畫;蝴蝶飛行時(shí)的位置改變是補(bǔ)間動(dòng)畫。
<!-- \res\anim\butterfly.xml -->
<?xml version="1.0" encoding="utf-8"?>
<!-- 定義動(dòng)畫循環(huán)播放 -->
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"android:oneshot="false"><item android:drawable="@drawable/butterfly_f01" android:duration="120" /><item android:drawable="@drawable/butterfly_f02" android:duration="120" /><item android:drawable="@drawable/butterfly_f03" android:duration="120" /><item android:drawable="@drawable/butterfly_f04" android:duration="120" /><item android:drawable="@drawable/butterfly_f05" android:duration="120" /><item android:drawable="@drawable/butterfly_f06" android:duration="120" />
</animation-list> 定義了上面逐幀動(dòng)畫的動(dòng)畫資源后,接下來(lái)在程序中使用一個(gè)ImageView顯示該動(dòng)畫資源即可。
這就可以看到蝴蝶“振翅”效果了。由于蝴蝶飛舞主要是位移改變,接下來(lái)可以在程序中通過(guò)
TranslateAnimation以動(dòng)畫的方式改變ImageView的位置,這樣就達(dá)到蝴蝶飛舞的效果了。
<ImageViewandroid:id="@+id/butterfly"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@anim/butterfly" /> public class Butterfly extends Activity {// 記錄蝴蝶ImageView當(dāng)前的位置private float curX = 0;private float curY = 30;// 記錄蝴蝶ImageView下一個(gè)位置的座標(biāo)float nextX = 0;float nextY = 0;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);// 獲取顯示蝴蝶的ImageView組件final ImageView imageView = (ImageView) findViewById(R.id.butterfly);final Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {if (msg.what == 0x123) {// 橫向上一直向右飛if (nextX > 320) {curX = nextX = 0;} else {nextX += 8;}// 縱向上可以隨機(jī)上下nextY = curY + (float) (Math.random() * 10 - 5);// 設(shè)置顯示蝴蝶的ImageView發(fā)生位移改變TranslateAnimation anim = new TranslateAnimation(curX,nextX, curY, nextY);curX = nextX;curY = nextY;anim.setDuration(200);// 開(kāi)始位移動(dòng)畫imageView.startAnimation(anim); // ①
}}};final AnimationDrawable butterfly = (AnimationDrawable) imageView.getBackground();imageView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// 開(kāi)始播放蝴蝶振翅的逐幀動(dòng)畫butterfly.start();// ②// 通過(guò)定制器控制每0.2秒運(yùn)行一次TranslateAnimation動(dòng)畫new Timer().schedule(new TimerTask() {@Overridepublic void run() {handler.sendEmptyMessage(0x123);}}, 0, 200);}});}
} ? ? ? ?上面程序①位于Handler的消息處理方法內(nèi),這樣程序每隔0.2秒即對(duì)該ImageView執(zhí)行一次位移動(dòng)畫;
程序②,用于播放butterfly動(dòng)畫(蝴蝶振翅效果)。運(yùn)行上面程序,單擊蝴蝶,即可看到屏幕有只蝴蝶從左向右飛舞。
13、自定義補(bǔ)間動(dòng)畫
? ? ? ?Android提供了Animation作為補(bǔ)間動(dòng)畫抽象基類。而且為該抽象基類提供了AlphaAnimation、RotateAnimation、
ScaleAnimation、TranslateAnimation四個(gè)實(shí)現(xiàn)類。這四個(gè)實(shí)現(xiàn)類只是補(bǔ)間動(dòng)畫的四種基本形式:透明度改變、旋轉(zhuǎn)、
縮放、位移,在實(shí)際項(xiàng)目中可能還需要一些更復(fù)雜的動(dòng)畫,比如讓圖片在"三維"空間內(nèi)進(jìn)行旋轉(zhuǎn)動(dòng)畫等。這就需要開(kāi)發(fā)
著自己開(kāi)發(fā)補(bǔ)間動(dòng)畫了。
import android.graphics.Camera;
import android.graphics.Matrix;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.Transformation;// 自定義動(dòng)畫類
public class MyAnimation extends Animation {private float centerX;private float centerY;// 定義動(dòng)畫的持續(xù)事件private int duration;private Camera camera = new Camera();public MyAnimation(float x, float y, int duration) {this.centerX = x;this.centerY = y;this.duration = duration;}@Overridepublic void initialize(int width, int height, int parentWidth,int parentHeight) {super.initialize(width, height, parentWidth, parentHeight);// 設(shè)置動(dòng)畫的持續(xù)時(shí)間
setDuration(duration);// 設(shè)置動(dòng)畫結(jié)束后效果保留setFillAfter(true);setInterpolator(new LinearInterpolator());}/** 該方法的interpolatedTime代表了抽象的動(dòng)畫持續(xù)時(shí)間,不管動(dòng)畫實(shí)際持續(xù)時(shí)間多長(zhǎng),* interpolatedTime參數(shù)總是從0(動(dòng)畫開(kāi)始時(shí))~1(動(dòng)畫結(jié)束時(shí)) Transformation參數(shù)代表了對(duì)目標(biāo)組件所做的變.*/@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {camera.save();// 根據(jù)interpolatedTime時(shí)間來(lái)控制X、Y、Z上的偏移camera.translate(100.0f - 100.0f * interpolatedTime,150.0f * interpolatedTime - 150,80.0f - 80.0f * interpolatedTime);// 設(shè)置根據(jù)interpolatedTime時(shí)間在Y柚上旋轉(zhuǎn)不同角度。camera.rotateY(360 * (interpolatedTime));// 設(shè)置根據(jù)interpolatedTime時(shí)間在X柚上旋轉(zhuǎn)不同角度camera.rotateX((360 * interpolatedTime));// 獲取Transformation參數(shù)的Matrix對(duì)象Matrix matrix = t.getMatrix();camera.getMatrix(matrix);matrix.preTranslate(-centerX, -centerY);matrix.postTranslate(centerX, centerY);camera.restore();}
} 1 import android.app.Activity;
2 import android.os.Bundle;
3 import android.util.DisplayMetrics;
4 import android.view.Display;
5 import android.view.WindowManager;
6 import android.widget.ListView;
7
8 public class ListViewTween extends Activity {
9 @Override
10 public void onCreate(Bundle savedInstanceState) {
11 super.onCreate(savedInstanceState);
12 setContentView(R.layout.main);
13 // 獲取ListView組件
14 ListView list = (ListView) findViewById(R.id.list);
15 WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
16 Display display = windowManager.getDefaultDisplay();
17 DisplayMetrics metrice = new DisplayMetrics();
18 // 獲取屏幕的寬和高
19 display.getMetrics(metrice);
20 // 設(shè)置對(duì)ListView組件應(yīng)用動(dòng)畫
21 list.setAnimation(new MyAnimation(metrice.xdpi / 2, metrice.ydpi / 2,
22 3500));
23 }
24 } <!-- main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical" ><ListViewandroid:id="@+id/list"android:layout_width="fill_parent"android:layout_height="fill_parent"android:entries="@array/bookArray" />
</LinearLayout> <!-- res/values/arrays.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<resources><string-array name="bookArray"><item>瘋狂Java講義</item><item>輕量級(jí)Java EE企業(yè)應(yīng)用實(shí)戰(zhàn)</item><item>經(jīng)典Java EE企業(yè)應(yīng)用實(shí)戰(zhàn)</item><item>瘋狂Ajax講義</item><item>瘋狂Android講義</item></string-array>
</resources> ?
總結(jié)
以上是生活随笔為你收集整理的八、图形与图像处理(2)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。