本站文章均為?李華明Himi? 原創(chuàng),轉(zhuǎn)載務(wù)必在明顯處注明:
轉(zhuǎn)載自 【黑米GameDev街區(qū)】 ?原文鏈接:? http://www.himigame.com/android-game/331.html ?
??? 之前在【Android2D游戲開(kāi)發(fā)之四】中我給大家介紹了一張13幀的png的圖,利用設(shè)置可視區(qū)域的方式來(lái)實(shí)現(xiàn)動(dòng)畫(huà)效果,但是這些屬于我們自己來(lái)實(shí)現(xiàn)動(dòng)畫(huà)的方式,其實(shí)Android給我們的有兩類(lèi)自定義動(dòng)畫(huà)方式:?
第一類(lèi):Frame By Frame 幀動(dòng)畫(huà) ( 不推薦游戲開(kāi)發(fā)中使用)
??? 所謂幀動(dòng)畫(huà),就是順序播放事先做好的圖像,類(lèi)似于放電影;
??? 分析: 此種方式類(lèi)似我之前的那種利用設(shè)置可視區(qū)域的方式來(lái)實(shí)現(xiàn)動(dòng)畫(huà)效果,不僅類(lèi)似而且還不如!所以此種方式在此不予分析;
?第二類(lèi):Tween Animation 漸變動(dòng)畫(huà)
??? 即通過(guò)對(duì)對(duì)象不斷做圖像變換( 平移、縮放、旋轉(zhuǎn)) 產(chǎn)生動(dòng)畫(huà)效果!實(shí)現(xiàn)方式其實(shí)就是預(yù)先定義一組指令,這些指令指定了圖形變換的類(lèi)型、觸發(fā)時(shí)間、持續(xù)時(shí)間。這些指令可以是以 XML 文件方式定義,也可以是以源代碼方式定義。程序沿著時(shí)間線執(zhí)行這些指令就可以實(shí)現(xiàn)動(dòng)畫(huà) 效果。
???? 總結(jié): 那么在Android 游戲開(kāi)發(fā)中我們優(yōu)先選用兩種方式:第一種設(shè)置可視區(qū)域的方式來(lái)實(shí)現(xiàn)動(dòng)畫(huà)效果(幀動(dòng)畫(huà)),需要童鞋們手動(dòng)實(shí)現(xiàn),那么在之前我的博文【Android2D游戲開(kāi)發(fā)之四】中已經(jīng)有了相應(yīng)的源碼!大家可以去下載研究;那么這里就主要為大家詳細(xì)分析 Tween Animation!?
??? 在講述SurfaceView添加動(dòng)畫(huà)之前,我們先來(lái)看看在View中如何實(shí)現(xiàn)Tween Animation以及Tween 中的四種效果;?
MyViewAnimation .java
package?com.himi.frameAnimation;?? ? import?android.content.Context;?? ? import?android.graphics.Bitmap;?? ? import?android.graphics.BitmapFactory;?? ? import?android.graphics.Canvas;?? ? import?android.graphics.Color;?? ? import?android.graphics.Paint;?? ? import?android.view.KeyEvent;?? ? import?android.view.View;?? ? import?android.view.animation.AlphaAnimation;?? ? import?android.view.animation.Animation;?? ? import?android.view.animation.RotateAnimation;?? ? import?android.view.animation.ScaleAnimation;?? ? import?android.view.animation.TranslateAnimation;?? ? /**? ? ?*@author?Himi? ? ?*@AlphaAnimation?漸變透明度動(dòng)畫(huà)效果? ? ?*@ScaleAnimation?漸變尺寸伸縮動(dòng)畫(huà)效果? ? ?*@TranslateAnimation?畫(huà)面轉(zhuǎn)換位置移動(dòng)動(dòng)畫(huà)效果? ? ?*@RotateAnimation?畫(huà)面轉(zhuǎn)移旋轉(zhuǎn)動(dòng)畫(huà)效果? ? ?*/?? ? public?class?MyViewAnimation?extends?View?{?? ? ????private?Paint?paint;?? ? ????private?Bitmap?bmp;?? ? ????private?int?x ?=?50 ;?? ? ????private?Animation?mAlphaAnimation;?? ? ????private?Animation?mScaleAnimation;?? ? ????private?Animation?mTranslateAnimation;?? ? ????private?Animation?mRotateAnimation;?? ? ????public?MyViewAnimation(Context?context)?{?? ? ????????super(context);?? ? ????????paint ?=?new ?Paint();?? ? ????????paint.setAntiAlias(true);?? ? ????????bmp ?=?BitmapFactory .decodeResource(getResources(),?R.drawable.icon);?? ? ????????this.setFocusable(true);//只有當(dāng)該View獲得焦點(diǎn)時(shí)才會(huì)調(diào)用onKeyDown方法??? ? ????}?? ? ????@Override?? ? ????protected?void?onDraw(Canvas?canvas)?{?? ? ????????super.onDraw(canvas);?? ? ????????canvas.drawColor(Color.BLACK);?? ? ????????paint.setColor(Color.WHITE);?? ? ????????canvas.drawText("Himi",?x,?50,?paint);//備注1?? ? ????????canvas.drawText("方向鍵↑?漸變透明度動(dòng)畫(huà)效果",?80,?this.getHeight()?-?80,?paint);?? ? ????????canvas.drawText("方向鍵↓?漸變尺寸伸縮動(dòng)畫(huà)效果",?80,?this.getHeight()?-?60,?paint);?? ? ????????canvas.drawText("方向鍵←?畫(huà)面轉(zhuǎn)換位置移動(dòng)動(dòng)畫(huà)效果",?80,?this.getHeight()?-?40,?paint);?? ? ????????canvas.drawText("方向鍵→?畫(huà)面轉(zhuǎn)移旋轉(zhuǎn)動(dòng)畫(huà)效果",?80,?this.getHeight()?-?20,?paint);?? ? ????????canvas.drawBitmap(bmp,?this.getWidth()?/?2?-?bmp.getWidth()?/?2,??? ? ????????????????this.getHeight()?/?2?-?bmp.getHeight()?/?2,?paint);?? ? ????????x?+=?1;?? ? ????}?? ? ????public?boolean?onKeyDown(int?keyCode,?KeyEvent?event)?{?? ? ????????if?(keyCode ?==?KeyEvent.KEYCODE_DPAD_UP)?{//漸變透明度動(dòng)畫(huà)效果?? ? ????????????mAlphaAnimation ?=?new ?AlphaAnimation(0.1f,?1.0f);?? ? ????????????//第一個(gè)參數(shù)fromAlpha?為動(dòng)畫(huà)開(kāi)始時(shí)候透明度?? ? ????????????//第二個(gè)參數(shù)toAlpha?為動(dòng)畫(huà)結(jié)束時(shí)候透明度?? ? ????????????//注意:取值范圍[0-1];[完全透明-完全不透明]?? ? ????????????mAlphaAnimation.setDuration(3000);?? ? ????????????設(shè)置時(shí)間持續(xù)時(shí)間為3000?毫秒=3秒?? ? ????????????this.startAnimation(mAlphaAnimation);?? ? ????????}?else?if?(keyCode ?==?KeyEvent.KEYCODE_DPAD_DOWN)?{//漸變尺寸伸縮動(dòng)畫(huà)效果?? ? ????????????mScaleAnimation ?=?new ?ScaleAnimation(0.0f,?1.5f,?0.0f,?1.5f,?Animation?? ? ????????????????????.RELATIVE_TO_PARENT,?0.5f,?Animation.RELATIVE_TO_PARENT,?0.0f);?? ? ????????????//第一個(gè)參數(shù)fromX為動(dòng)畫(huà)起始時(shí)X坐標(biāo)上的伸縮尺寸?? ? ????????????//第二個(gè)參數(shù)toX為動(dòng)畫(huà)結(jié)束時(shí)X坐標(biāo)上的伸縮尺寸?? ? ????????????//第三個(gè)參數(shù)fromY為動(dòng)畫(huà)起始時(shí)Y坐標(biāo)上的伸縮尺寸?? ? ????????????//第四個(gè)參數(shù)toY?為動(dòng)畫(huà)結(jié)束時(shí)Y?坐標(biāo)上的伸縮尺寸?? ? ????????????//注意:?? ? ????????????//0.0表示收縮到?jīng)]有?? ? ????????????//1.0表示正常無(wú)伸縮?? ? ????????????//值小于1.0表示收縮?? ? ????????????//值大于1.0表示放大?? ? ????????????//-----我這里1-4參數(shù)表明是起始圖像大小不變,動(dòng)畫(huà)終止的時(shí)候圖像被放大1.5倍?? ? ????????????//第五個(gè)參數(shù)pivotXType?為動(dòng)畫(huà)在X?軸相對(duì)于物件位置類(lèi)型?? ? ????????????//第六個(gè)參數(shù)pivotXValue?為動(dòng)畫(huà)相對(duì)于物件的X?坐標(biāo)的開(kāi)始位置?? ? ????????????//第七個(gè)參數(shù)pivotXType?為動(dòng)畫(huà)在Y?軸相對(duì)于物件位置類(lèi)型?? ? ????????????//第八個(gè)參數(shù)pivotYValue?為動(dòng)畫(huà)相對(duì)于物件的Y?坐標(biāo)的開(kāi)始位置?? ? ????????????//提示:位置類(lèi)型有三種,每種效果大家自己嘗試哈~這里偷下懶~?? ? ????????????//畢竟親眼看到效果的區(qū)別才記憶深刻~?? ? ????????????//Animation.ABSOLUTE?、Animation.RELATIVE_TO_SELF、Animation.RELATIVE_TO_PARENT?? ? ????????????mScaleAnimation.setDuration(2000);?? ? ????????????this.startAnimation(mScaleAnimation);?? ? ????????}?else?if?(keyCode ?==?KeyEvent.KEYCODE_DPAD_LEFT)?{//畫(huà)面轉(zhuǎn)換位置移動(dòng)動(dòng)畫(huà)效果?? ? ????????????mTranslateAnimation ?=?new ?TranslateAnimation(0,?100,?0,?100);?? ? ????????????//第一個(gè)參數(shù)fromXDelta為動(dòng)畫(huà)起始時(shí)X坐標(biāo)上的移動(dòng)位置?? ? ????????????//第二個(gè)參數(shù)toXDelta為動(dòng)畫(huà)結(jié)束時(shí)X坐標(biāo)上的移動(dòng)位置?? ? ????????????//第三個(gè)參數(shù)fromYDelta為動(dòng)畫(huà)起始時(shí)Y坐標(biāo)上的移動(dòng)位置?? ? ????????????//第四個(gè)參數(shù)toYDelta?為動(dòng)畫(huà)結(jié)束時(shí)Y?坐標(biāo)上的移動(dòng)位置?? ? ????????????mTranslateAnimation.setDuration(2000);?? ? ????????????this.startAnimation(mTranslateAnimation);?? ? ????????}?else?if?(keyCode ?==?KeyEvent.KEYCODE_DPAD_RIGHT)?{//畫(huà)面轉(zhuǎn)移旋轉(zhuǎn)動(dòng)畫(huà)效果?? ? ????????????mRotateAnimation ?=?new ?RotateAnimation(0.0f,?360.0f,??? ? ????????????????Animation.RELATIVE_TO_SELF,?0.5f,?Animation.RELATIVE_TO_SELF,?0.5f);?? ? ????????????//第一個(gè)參數(shù)fromDegrees為動(dòng)畫(huà)起始時(shí)的旋轉(zhuǎn)角度?? ? ????????????//第二個(gè)參數(shù)toDegrees?為動(dòng)畫(huà)旋轉(zhuǎn)到的角度?? ? ????????????//第三個(gè)參數(shù)pivotXType?為動(dòng)畫(huà)在X?軸相對(duì)于物件位置類(lèi)型?? ? ????????????//第四個(gè)參數(shù)pivotXValue?為動(dòng)畫(huà)相對(duì)于物件的X?坐標(biāo)的開(kāi)始位置?? ? ????????????//第五個(gè)參數(shù)pivotXType?為動(dòng)畫(huà)在Y?軸相對(duì)于物件位置類(lèi)型?? ? ????????????//第六個(gè)參數(shù)pivotYValue?為動(dòng)畫(huà)相對(duì)于物件的Y?坐標(biāo)的開(kāi)始位置?? ? ????????????mRotateAnimation.setDuration(3000);?? ? ????????????this.startAnimation(mRotateAnimation);?? ? ????????}?? ? ????????return?super.onKeyDown(keyCode,?event);?? ? ????}?? ? }? ?補(bǔ)充:有童鞋說(shuō)對(duì)三種相對(duì)位置不太理解,那么我簡(jiǎn)單說(shuō)補(bǔ)充下:
//Animation.ABSOLUTE 相對(duì)位置是屏幕左上角,絕對(duì)位置! //Animation.RELATIVE_TO_SELF 相對(duì)位置是自身View;取值為0,是自身左上角,取值為1是自身的右下角; //Animation.RELATIVE_TO_PARENT 相對(duì)父類(lèi)View的位置
當(dāng)設(shè)定了位置類(lèi)型之后,會(huì)讓你傳入X或者Y的值,這里的X,Y可以理解成為一個(gè)點(diǎn)坐標(biāo)!比如是旋轉(zhuǎn)動(dòng)畫(huà),那么這個(gè)(X,Y)就是旋轉(zhuǎn)中心點(diǎn)!
??? OK,對(duì)于Tween Animation下的每種動(dòng)畫(huà)效果的實(shí)例化的每個(gè)參數(shù)都解釋的很詳細(xì)了!其實(shí)動(dòng)畫(huà)的實(shí)現(xiàn)不光用代碼可以實(shí)現(xiàn),在xml中注冊(cè)實(shí)現(xiàn)也是可以的,這里就不多寫(xiě)了,大家可以自己去嘗試寫(xiě)一下,那么在view中我們播放一種特效動(dòng)畫(huà),只要實(shí)例化其對(duì)象,然后設(shè)置下參數(shù),然后startAnimation()就好了,步驟很簡(jiǎn)單,只是每個(gè)動(dòng)畫(huà)實(shí)例化的參數(shù)確有著千變?nèi)f化的改法,這些我也沒(méi)法子一一來(lái)給大家演示,大家可以自己改改參數(shù)看看實(shí)際的效果!當(dāng)然對(duì)于每種動(dòng)畫(huà)我們不光有設(shè)置播放的時(shí)候,還有一些屬性和方法可以調(diào)用,比如Animation.restart()重放動(dòng)畫(huà),getTransformation()此方法返回 假,說(shuō)明動(dòng)畫(huà)完成等等很多屬性,請(qǐng)各位童鞋自定實(shí)驗(yàn) o(∩_∩)o 哈哈~
???? 順便先解釋下MyViewAnimation .java 類(lèi)中onDraw()方法里的( 備注1) !其實(shí)這里我是想跟大家說(shuō)明下Android Animation實(shí)現(xiàn)機(jī)制
【啟動(dòng)任意一種動(dòng)畫(huà)效果之前 和 之后 的對(duì)比圖】?
???? 很明顯、"Himi"字樣在動(dòng)畫(huà)開(kāi)始前和開(kāi)始后出現(xiàn)了移動(dòng),而且在MyViewAnimation.java中我沒(méi)有使用Runnable接口,也沒(méi)有調(diào)用刷新的函數(shù),那么我來(lái)給各位童鞋解釋下原因:?
??? 動(dòng)畫(huà)的每種變換其實(shí)內(nèi)部都是一次矩陣運(yùn)算。在Android 中,Canvas 類(lèi)中包含當(dāng)前矩陣,當(dāng)調(diào)用 Canvas.drawBitmap (bmp, x, y, Paint) 繪制時(shí),android 會(huì)先把 bmp 做一次矩陣運(yùn)算,然后將運(yùn)算的結(jié)果顯示在 Canvas 上,然后不斷修改 Canvas 的矩陣并刷新屏幕,View 里的對(duì)象就會(huì)不停的做圖形變換,動(dòng)畫(huà)就形成了。
???? 還有一點(diǎn)提醒大家:動(dòng)畫(huà)的播放是對(duì)整個(gè)游戲畫(huà)布進(jìn)行的操作,這一點(diǎn)要知道喲~
???? 那么下面就要給大家介紹如何在我們的SurfaceView中運(yùn)用Tween Animation!
MySurfaceViewAnimation.java?
package?com.himi.frameAnimation; ? import?android.content.Context; ? import?android.graphics.Bitmap; ? import?android.graphics.BitmapFactory; ? import?android.graphics.Canvas; ? import?android.graphics.Color;? ? import?android.graphics.Paint;? ? import?android.util.Log; ? import?android.view.KeyEvent; ? import?android.view.SurfaceHolder; ? import?android.view.SurfaceView; ? import?android.view.SurfaceHolder.Callback; ? import?android.view.animation.AlphaAnimation; ? import?android.view.animation.Animation; ? import?android.view.animation.RotateAnimation; ? import?android.view.animation.ScaleAnimation;? ? import?android.view.animation.TranslateAnimation; ? /** ? ?*@author?Himi ? ?*/ ? public?class?MySurfaceViewAnimation?extends?SurfaceView?implements?Callback,?Runnable?{ ? ????private?Thread?th ?=?new ?Thread(this); ? ????private?SurfaceHolder?sfh; ? ????private?Canvas?canvas; ? ????private?Paint?paint; ? ????private?Bitmap?bmp; ? ????///? ? private?Animation?mAlphaAnimation; ? private?Animation?mScaleAnimation; ? private?Animation?mTranslateAnimation; ? private?Animation?mRotateAnimation; ? public?MySurfaceViewAnimation(Context?context)?{ ? ????super(context); ? ????Log.v("Himi",?"MySurfaceView"); ? ????this.setKeepScreenOn(true); ? ????bmp ?=?BitmapFactory .decodeResource(getResources(),?R.drawable.icon); ? ????sfh ?=?this .getHolder(); ? ????sfh.addCallback(this); ? ????paint ?=?new ?Paint(); ? ????paint.setAntiAlias(true); ? ????setFocusable(true); ? ????setFocusableInTouchMode(true); ? //??this.setBackgroundResource(R.drawable.icon);//備注2 ? } ? public?void?surfaceCreated(SurfaceHolder?holder)?{ ? ????Log.v("Himi",?"surfaceCreated"); ? ????th.start(); ? } ? public?void?draw()?{ ? ????try?{ ? ????????canvas ?=?sfh .lockCanvas(); ? ????????if?(canvas?!=?null)?{ ? ????????????canvas.drawColor(Color.BLACK); ? ????????????paint.setColor(Color.WHITE); ? ????????????canvas.drawText("方向鍵↑?漸變透明度動(dòng)畫(huà)效果",?80,?this.getHeight()?-?80,?paint); ? ????????????canvas.drawText("方向鍵↓?漸變尺寸伸縮動(dòng)畫(huà)效果",?80,?this.getHeight()?-?60,?paint); ? ????????????canvas.drawText("方向鍵←?畫(huà)面轉(zhuǎn)換位置移動(dòng)動(dòng)畫(huà)效果",?80,?this.getHeight()?-?40,?paint); ? ????????????canvas.drawText("方向鍵→?畫(huà)面轉(zhuǎn)移旋轉(zhuǎn)動(dòng)畫(huà)效果",?80,?this.getHeight()?-?20,?paint); ? ????????????canvas.drawBitmap(bmp,?this.getWidth()?/?2?-?bmp.getWidth()?/?2,? ? ????????????????????this.getHeight()?/?2?-?bmp.getHeight()?/?2,?paint); ? ????????} ? ????}?catch?(Exception?e)?{ ? ????????Log.v("Himi",?"draw?is?Error!"); ? ????}?finally?{ ? ????????sfh.unlockCanvasAndPost(canvas); ? ????} ? } ? @Override ? public?boolean?onKeyDown(int?keyCode,?KeyEvent?event)?{ ? ????if?(keyCode ?==?KeyEvent.KEYCODE_DPAD_UP)?{//漸變透明度動(dòng)畫(huà)效果 ? ????????mAlphaAnimation ?=?new ?AlphaAnimation(0.1f,?1.0f); ? ????????mAlphaAnimation.setDuration(3000); ? ????????this.startAnimation(mAlphaAnimation); ? ????}?else?if?(keyCode ?==?KeyEvent.KEYCODE_DPAD_DOWN)?{//漸變尺寸伸縮動(dòng)畫(huà)效果 ? ????????mScaleAnimation ?=?new ?ScaleAnimation(0.0f,?2.0f,? ? ????????????????1.5f,?1.5f,?Animation.RELATIVE_TO_PARENT,? ? ????????????????0.5f,?Animation.RELATIVE_TO_PARENT,?0.0f); ? ????????mScaleAnimation.setDuration(2000); ? ????????this.startAnimation(mScaleAnimation); ? ????}?else?if?(keyCode ?==?KeyEvent.KEYCODE_DPAD_LEFT)?{//畫(huà)面轉(zhuǎn)換位置移動(dòng)動(dòng)畫(huà)效果 ? ????????mTranslateAnimation ?=?new ?TranslateAnimation(0,?100,?0,?100); ? ????????mTranslateAnimation.setDuration(2000); ? ????????this.startAnimation(mTranslateAnimation); ? ????}?else?if?(keyCode ?==?KeyEvent.KEYCODE_DPAD_RIGHT)?{//畫(huà)面轉(zhuǎn)移旋轉(zhuǎn)動(dòng)畫(huà)效果 ? ????????mRotateAnimation ?=?new ?RotateAnimation(0.0f,?360.0f,? ? ????????????????Animation.RELATIVE_TO_SELF,?0.5f,?Animation.RELATIVE_TO_SELF,?0.5f); ? ????????mRotateAnimation.setDuration(3000); ? ????????this.startAnimation(mRotateAnimation); ? ????} ? ????return?super.onKeyDown(keyCode,?event); ? } ? public?void?run()?{ ? ????//?TODO?Auto-generated?method?stub ? ????while?(true)?{ ? ????????draw(); ? ????????try?{ ? ????????????Thread.sleep(100); ? ????????}?catch?(Exception?ex)?{ ? ????????} ? ????} ? } ? public?void?surfaceChanged(SurfaceHolder?holder,?int?format,?int?width,?int?height)?{ ? ????Log.v("Himi",?"surfaceChanged"); ? } ? public?void?surfaceDestroyed(SurfaceHolder?holder)?{ ? ????Log.v("Himi",?"surfaceDestroyed"); ? ????} ? }? ?
???? 動(dòng)畫(huà)代碼實(shí)現(xiàn)跟View中的做法一樣,運(yùn)行模擬器發(fā)現(xiàn)按鍵沒(méi)效果,不是按鍵沒(méi)觸發(fā)是本來(lái)就存在問(wèn)題, - -。但是!大家可以把此類(lèi)里有一行,也就是(備注2) 的注釋打開(kāi),我們給設(shè)置背景圖,然后在模擬器上的運(yùn)行效果如下圖:?
???? 很明顯的看到,我們的動(dòng)畫(huà)正常運(yùn)行了,雖然效果并不是我們想到的!但是這里可以說(shuō)明一點(diǎn)問(wèn)題:
SurfaceView 本身具備雙緩沖機(jī)制!!!!!
??? 有些文章里說(shuō)“給SurfaceView添加雙緩沖”,其實(shí)是在畫(huà)蛇添足 - -,而且介紹的時(shí)候拿著單線程與雙線程例子來(lái)解釋雙緩沖更高效的實(shí)現(xiàn)方法;我想弱弱的問(wèn)什么是雙緩沖??? 如果SurfaceView不具備雙緩沖,那敢問(wèn)上面這張截圖如何解釋????
??? 其實(shí)要實(shí)現(xiàn)雙緩沖,只需要是新建一個(gè)Bitmap和Canvas,用這個(gè)新建的Canvas把正弦波畫(huà)到新建的Bitmap,畫(huà)完再通過(guò)sfh.lockCanvas獲取SurfaceView對(duì)應(yīng)的Canvas,用這個(gè)Canvas把新建的Bitmap畫(huà)到SurfaceView上去,這才叫雙緩沖; 還有雙緩存和多線程沒(méi)關(guān)系!?
??? 那么View中動(dòng)畫(huà)的實(shí)現(xiàn)機(jī)制是在不斷的刷屏不斷的重復(fù)調(diào)用重寫(xiě)的onDraw()方法、而在Surfaceview的那張截圖確實(shí)也正常的動(dòng)畫(huà)操作了,原因又何在?而且我們?cè)O(shè)置的背景圖覆蓋我們draw出來(lái)的字體!!效果很不理想;那么經(jīng)過(guò)考慮我決定利用布局把View和SurfaceView都一并顯示,用View主要去完成動(dòng)畫(huà)部分,(那么關(guān)于如何一并顯示,或者說(shuō)同時(shí)在SurfaceView中添加組件,在之前的【Android 2D開(kāi)發(fā)之六】 和 【Android 2D開(kāi)發(fā)之七】都有了詳細(xì)講解,那么在這里),當(dāng)然一并顯示也會(huì)有問(wèn)題,比如我們存在了view和Surfaceiew,那么按鍵的時(shí)候觸發(fā)的哪個(gè)?或者說(shuō)如何去控制這兩個(gè)View?放心,我下面就跟大家一一來(lái)講解!
???? 下面先讓我們把我們的view 和 Surfaceview 先同時(shí)顯示出來(lái):【黑色的是MyView (View),白色是MySurfaceView(SurfaceView) 】?
先上張運(yùn)行截圖: (圖4) ?
main.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" ? ????> ? ? ????< RelativeLayout ? ????????????android:layout_width ="fill_parent" ? ????????????android:layout_height ="wrap_content" ? ????????????android:layout_weight ="1" ?> ? ???????< com.himi.MySurfaceView ?android:id ="@+id/view3d" ? ????????????android:layout_width ="fill_parent" ? ????????????android:layout_height ="fill_parent" /> ??? ? ????< com.himi.MyView ?android:id ="@+id/myview" ? ????????????android:layout_width ="fill_parent" ? ????????????android:layout_height ="fill_parent" /> ??? ? ????</ RelativeLayout > ??? ? </ LinearLayout > ? ?
??xml中我們注冊(cè)了我們自定義的view-MyView 和 SurfaceView-MySurfaceView;
需要強(qiáng)調(diào)的有兩點(diǎn):
??? 1 : 當(dāng)我們xml中注冊(cè)我們的View時(shí),我們View類(lèi)中的構(gòu)造函數(shù)必須要用 public MyView(Context context, AttributeSet attrs) {} 兩個(gè)參數(shù)的形式,以前的文章有講解。 ?
??? 2 : 當(dāng)我們?cè)赬ml中注冊(cè)兩個(gè)View的時(shí)候,它們顯示的次序就是根據(jù)xml注冊(cè)的順序來(lái)顯示,比如上面我們先注冊(cè)了 MySurfaceView, 然后注冊(cè)的 MyView ,那么顯示的時(shí)候會(huì)把后添加進(jìn)去的MyView顯示在最上層!
?下面我們來(lái)看MySurfaceView.java中的代碼:?
package?com.himi; ? import?android.content.Context; ? import?android.graphics.Canvas; ? import?android.graphics.Color; ? import?android.graphics.Paint; ? import?android.util.AttributeSet; ? import?android.view.KeyEvent;? ? import?android.view.SurfaceHolder; ? import?android.view.SurfaceView;? ? import?android.view.SurfaceHolder.Callback;?? ? /** ? ?*? ? ?*?@author?Himi ? ?* ? ?*/ ? public?class?MySurfaceView?extends?SurfaceView?implements?Callback,?Runnable?{ ? ????public?static?MySurfaceView?msrv?;//----備注1 ? ????private?int?move_x ?=?2 ,?x ?=?20 ; ? ????private?Thread?th; ? ????private?SurfaceHolder?sfh; ? ????private?Canvas?canvas; ? ????private?Paint?p;? ? ????public?MySurfaceView(Context?context,?AttributeSet?attrs)?{? ? ????????super(context,?attrs); ? ????????msrv =this ; ? ????????p ?=?new ?Paint();? ? ????????p.setAntiAlias(true); ? ????????sfh ?=?this .getHolder(); ? ????????sfh.addCallback(this); ? ????????th ?=?new ?Thread(this); ? ????????this.setKeepScreenOn(true);? ? ?????????this.setFocusable(true);//?----備注2 ? ????}? ? ????public?void?surfaceCreated(SurfaceHolder?holder)?{ ? ????????th.start();? ? ????}? ? ????public?void?draw()?{ ? ????????canvas ?=?sfh .lockCanvas(); ? ????????if(canvas!=null){ ? ????????????canvas.drawColor(Color.WHITE); ? ????????????canvas.drawText("我是???-?Surfaceview",?x?+?move_x,?280,?p); ? ????????????sfh.unlockCanvasAndPost(canvas); ? ????????}? ? ????} ? ????private?void?logic()?{?? ? ????????x?+=?move_x; ? ????????if?(x?> ?200?||?x?< ?80 )?{ ? ????????????move_x ?=?-move_x; ? ????????} ? ????} ? ????@Override ? ????public?boolean?onKeyDown(int?key,?KeyEvent?event)?{?//備注2 ? ????????return?super.onKeyDown(key,?event); ? ????}? ? ????? ? ????public?void?run()?{ ? ????????//?TODO?Auto-generated?method?stub ? ????????while?(true)?{ ? ????????????draw(); ? ????????????logic(); ? ????????????try?{ ? ????????????????Thread.sleep(100); ? ????????????}?catch?(Exception?ex)?{ ? ????????????} ? ????????} ? ????}?? ? ????public?void?surfaceChanged(SurfaceHolder?holder,?int?format,?int?width, ? ????????????int?height)?{? ? ????}? ? ????public?void?surfaceDestroyed(SurfaceHolder?holder)?{? ? ????} ? } ? ????? 代碼都很熟悉了, 主要我們來(lái)給大家解釋下備注1,備注2:
備注1:
??? 我在兩個(gè)MyView 和 MySurfaceView中都定義了本類(lèi)一個(gè)靜態(tài)對(duì)象,然后在初始化的時(shí)候都利用=this 的形式進(jìn)行了實(shí)例化;
??? 注意:=this; 的這種實(shí)例形式要注意!只能在當(dāng)前程序中僅存在一個(gè)本類(lèi)對(duì)象才可使用!
??? 為什么要實(shí)例兩個(gè)View的實(shí)例而且定義成靜態(tài),這樣做主要為了類(lèi)之間方便調(diào)用和操作!比如在我們這個(gè)項(xiàng)目中,我這樣做是為了在MainActivity中去管理兩個(gè)View按鍵焦點(diǎn)!下面我會(huì)給出MainActivity的代碼,大家一看便知;?
備注2:
??? 我在兩個(gè)MyView 和 MySurfaceView中都對(duì)獲取按鍵焦點(diǎn)注釋掉了,而是在別的類(lèi)中的調(diào)用其View的靜態(tài)實(shí)例對(duì)象就可以任意類(lèi)中對(duì)其設(shè)置!這樣就可以很容易去控制到底誰(shuí)來(lái)響應(yīng)按鍵了。
???? 這里還要強(qiáng)調(diào)一下:當(dāng)xml中注冊(cè)多個(gè) View的時(shí)候,當(dāng)我們點(diǎn)擊按鍵之后,Android會(huì)先判定哪個(gè)View setFocusable(true)設(shè)置焦點(diǎn)了,如果都設(shè)置了,那么Android 會(huì)默認(rèn)響應(yīng)在xml中第一個(gè)注冊(cè)的view ,而不是兩個(gè)都會(huì)響應(yīng)。那么為什么不同時(shí)響應(yīng)呢?我解釋下: ?
??? 上面這截圖是Android SDK Api的樹(shù)狀圖,很明顯SurfaceView繼承了View,它倆是基繼承關(guān)系,那么不管是子類(lèi)還是基類(lèi)一旦響應(yīng)了按鍵,其基類(lèi)或者父類(lèi)就不會(huì)再去響應(yīng);
?下面我們來(lái)看MainActivity.java:
package?com.himi; ? import?android.app.Activity; ? import?android.os.Bundle;? ? import?android.view.KeyEvent; ? import?android.view.Window; ? import?android.view.WindowManager; ? /** ? ?*? ? ?*?@author?Himi ? ?* ? ?*/ ? public?class?MainActivity?extends?Activity?{ ? ????/**?Called?when?the?activity?is?first?created.?*/? ? ????@Override ? ????public?void?onCreate(Bundle?savedInstanceState)?{ ? ????????super.onCreate(savedInstanceState); ? ????????this.requestWindowFeature(Window.FEATURE_NO_TITLE); ? ????????this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, ? ????????????????WindowManager.LayoutParams.FLAG_FULLSCREEN); ? ????????setContentView(R.layout.main);? ? ????????MySurfaceView.msrv.setFocusable(false);//備注1 ? ????????MyView.mv.setFocusable(true);//備注1 ? ????} ? ????@Override ? ????public?boolean?onKeyDown(int?keyCode,?KeyEvent?event)?{//備注2 ? ????????return?super.onKeyDown(keyCode,?event); ? ????} ? ???? ? }? ?
備注1:
??? 這里是當(dāng)程序運(yùn)行的時(shí)候我們默認(rèn)讓我們的MyView(View)來(lái)響應(yīng)按鍵。通過(guò)類(lèi)名調(diào)用對(duì)應(yīng)的View實(shí)例,然后設(shè)置獲取焦點(diǎn)的函數(shù);
備注2:
??? 這里要注意:不管你在xml中注冊(cè)了多少個(gè)View ,也不管View是否都設(shè)置了獲取焦點(diǎn),只要你在 MainActivity 中重寫(xiě)onKeyDown()函數(shù),Android 就會(huì)調(diào)用此函數(shù)。 ?
??? 那么直接在SurfaceView中進(jìn)行實(shí)現(xiàn)動(dòng)畫(huà)的想法這里沒(méi)有得到很好的解決,而是我利用布局的方式來(lái)一同顯示的方式,希望各位童鞋如果有好的方法,在SurfaceView中直接能使用動(dòng)畫(huà)的建議和想法,希望留言給我,大家一起學(xué)習(xí) 討論,謝謝 下面給出項(xiàng)目源碼:
?源碼下載地址:? http://www.himigame.com/android-game/331.html
(歡迎各位童鞋訂閱本博客,因?yàn)樵鄣母滤俣瓤墒呛芸斓膥娃哈哈)
總結(jié)
以上是生活随笔 為你收集整理的【Android游戏开发十四】深入Animation,在SurfaceView中照样使用Android—Tween Animation!... 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。