《Android 应用案例开发大全(第3版)》——第2.4节壁纸的实现
本節(jié)書摘來自異步社區(qū)《Android 應(yīng)用案例開發(fā)大全(第3版)》一書中的第2章,第2.4節(jié)壁紙的實(shí)現(xiàn),作者 吳亞峰 , 蘇亞光 , 于復(fù)興,更多章節(jié)內(nèi)容可以訪問云棲社區(qū)“異步社區(qū)”公眾號(hào)查看
2.4 壁紙的實(shí)現(xiàn)
上一節(jié)介紹了壁紙的框架,讓讀者對(duì)3D動(dòng)態(tài)壁紙的整體框架有了初步認(rèn)識(shí),本節(jié)將要對(duì)動(dòng)態(tài)壁紙的實(shí)現(xiàn)服務(wù)類GLWallpaperService和OpenGLES2WallpaperService以及自定義場(chǎng)景渲染器類MySurfaceView的開發(fā)進(jìn)行詳細(xì)介紹。
2.4.1 壁紙服務(wù)類——OpenGLES2WallpaperService
這兩個(gè)類是本項(xiàng)目中最基礎(chǔ)的類,沒有這兩個(gè)類就不可能使用壁紙。GLWallpaperService類為開發(fā)人員提供了壁紙服務(wù),OpenGLES2WallpaperService通過繼承GLWallpaperService類,重寫此類中的方法來實(shí)現(xiàn)壁紙的后續(xù)開發(fā)。下面著重介紹一下OpenGLES2WallpaperService類中的onCreate方法和GLWallpaperService類中的觸控響應(yīng)事件onTouchEvent。
(1)首先是OpenGLES2WallpaperService類中的onCreate方法,onCreate方法是OpenGLES2 WallpaperService類的核心部分,其中包括獲取當(dāng)前手機(jī)的配置信息,并且判斷其是否支持OPENGL ES2.0渲染技術(shù)等。具體代碼如下所示。
1 public void onCreate(SurfaceHolder surfaceHolder) { 2 super.onCreate(surfaceHolder); 3 final ActivityManager activityManager = //創(chuàng)建Activity管理器 4 (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 5 final ConfigurationInfo configurationInfo = //獲取當(dāng)前機(jī)器配置信息 6 activityManager.getDeviceConfigurationInfo(); 7 final boolean supportsEs2 = //獲取判斷結(jié)果 8 configurationInfo.reqGlEsVersion >= 0x20000; 9 if (supportsEs2) { 10 setEGLContextClientVersion(2); //設(shè)置使用OPENGL ES2.0 11 setPreserveEGLContextOnPause(true);//EGL跨越暫停/恢復(fù)界限來嘗試和保存環(huán)境 12 setRenderer(getNewRenderer()); //設(shè)置渲染器 13 } else {return;} 14 }第3~8行用于創(chuàng)建Activity管理器,獲取配置信息,判斷當(dāng)前手機(jī)是否支持OPENGL ES2.0渲染技術(shù),并將結(jié)果存儲(chǔ)在supportsEs2中。
第9~13行用于判斷supportsEs2中的值,如果當(dāng)前手機(jī)支持OPENGL ES2.0渲染技術(shù),則設(shè)置使用OPENGL ES2.0進(jìn)行繪制,并且讓EGL跨越暫停或恢復(fù)界限來嘗試和保護(hù)環(huán)境,然后設(shè)置場(chǎng)景渲染器;如果不支持OPENGL ES2.0,則退出繪制。
(2)下面將對(duì)屏幕觸控的響應(yīng)事件進(jìn)行介紹。屏幕的觸控事件分為3部分:第一部分是滑動(dòng)屏幕使背景圖跟著屏幕左右移動(dòng),第二部分是點(diǎn)擊屏幕下方修改標(biāo)志位,最后一部分是手指抬起時(shí)判斷是否進(jìn)行喂食,具體代碼如下所示。
第1~9行首先創(chuàng)建變量,用于記錄觸控筆上一次的觸控X位置和Y位置,然后獲取當(dāng)前觸控點(diǎn)的X坐標(biāo)和Y坐標(biāo),并且響應(yīng)屏幕的觸控事件,對(duì)ACTION_DOWN事件進(jìn)行監(jiān)聽,當(dāng)觸發(fā)時(shí)將喂食標(biāo)志位設(shè)為true。
第10~28行對(duì)ACTION_MOVE事件進(jìn)行監(jiān)聽,獲取手指在屏幕上的移動(dòng)距離,按照一定比例移動(dòng)攝像機(jī)X坐標(biāo),同時(shí),如果攝像機(jī)X坐標(biāo)達(dá)到閾值,則攝像機(jī)不會(huì)向滑動(dòng)方向移動(dòng);然后將攝像機(jī)的位置信息存入到矩陣中,設(shè)置攝像機(jī)的位置,觀測(cè)點(diǎn)的坐標(biāo)和up向量。
第30~37行是判斷喂食的標(biāo)志位,因?yàn)榛瑒?dòng)屏幕不能喂食,當(dāng)前喂的食物在沒有消失之前也不能喂食,所以需要兩個(gè)標(biāo)志位對(duì)其進(jìn)行控制。一個(gè)在點(diǎn)擊喂食的時(shí)候?yàn)閠rue,另一個(gè)在沒有喂食之前為true,然后通過矩陣變換獲取觸控點(diǎn)在世界坐標(biāo)系中的坐標(biāo)。
第38~47行通過拾取計(jì)算獲取觸控點(diǎn)在世界坐標(biāo)系中的起點(diǎn)(近平面點(diǎn))坐標(biāo)、終點(diǎn)(遠(yuǎn)平面點(diǎn))坐標(biāo),判斷feedfish不為空,則調(diào)用startFeed方法開始喂食;然后記錄觸控筆的X位置、Y位置,回調(diào)父類的方法。
2.4.2 自定義渲染器類——MySurfaceView
下面將詳細(xì)介紹自定義的場(chǎng)景渲染器代碼,在自定義的場(chǎng)景渲染器類里,可以進(jìn)行魚、魚群、烏龜、珍珠貝、氣泡、背景圖、魚食的初始化。初始化魚類和烏龜?shù)某跏妓俣取⒊跏嘉恢靡约凹虞d紋理等,并且設(shè)置光源位置,初始化矩陣等。
(1)由于MySurfaceView類中繪制代碼以及初始化代碼比較多,在此首先介紹該類的繪制代碼以及整體框架,使讀者對(duì)此類有一個(gè)大致的了解。具體代碼如下所示。
1 package wyf.lxg.mywallpaper; 2 .....//此處省略部分類和包的導(dǎo)入代碼,請(qǐng)讀者自行查閱隨書附帶光盤的源代碼 3 public class MySurfaceView extends GLSurfaceView 4 implements GLSurfaceView.Renderer,OpenGLES2WallpaperService.Renderer { 5 public MySurfaceView(Context context) { 6 super(context); //獲取上下文對(duì)象 7 this.setEGLContextClientVersion(2); //設(shè)置使用OPENGL ES2.0 8 } 9 .....//此處省略相關(guān)成員變量的聲明代碼,請(qǐng)讀者自行查閱隨書附帶光盤的源代碼 10 public void onDrawFrame(GL10 gl) { 11 GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT //清除深度緩沖與顏色緩沖 12 | GLES20.GL_COLOR_BUFFER_BIT); 13 MatrixState.pushMatrix(); //保護(hù)矩陣 14 if(bg!=null){ bg.drawSelf(back); } //繪制背景圖 15 if(singlefood!=null) { singlefood.drawSelf();} //繪制魚食 16 if (fishControl != null) { fishControl.drawSelf();} //繪制單條魚和烏龜 17 if (fishSchool != null) { fishSchool.drawSelf();} //繪制魚群 18 .....//此處繪制其他魚群的代碼與上述相似,故省略,請(qǐng)讀者自行查閱隨書附帶光盤的源代碼 19 MatrixState.pushMatrix(); //保護(hù)矩陣 20 MatrixState.translate(,-16,); //平移到指定位置 21 this.haibei.animate(time,dpm); //繪制珍珠貝 22 MatrixState.popMatrix(); //恢復(fù)矩陣 23 time += ; 24 if(time > this.ms3d.getTotalTime()) { //若當(dāng)前播放時(shí)間大于總的動(dòng)畫時(shí)間 25 time = time - this.ms3d.getTotalTime();//則播放時(shí)間等于當(dāng)前播放時(shí)間減去總的動(dòng)畫時(shí)間 26 } 27 MatrixState.popMatrix(); //恢復(fù)矩陣 28 GLES20.glEnable(GLES20.GL_BLEND); //開啟混合 29 GLES20.glBlendFunc(GLES20.GL_SRC_COLOR, //設(shè)置混合因子c 30 GLES20.GL_ONE_MINUS_SRC_COLOR); 31 MatrixState.pushMatrix(); //保護(hù)矩陣 32 if(bubble!=null) { bubble.drawSelf();} //繪制氣泡 33 MatrixState.popMatrix(); //恢復(fù)矩陣 34 GLES20.glDisable(GLES20.GL_BLEND); //關(guān)閉混合 35 } 36 public void onSurfaceChanged(GL10 gl, int width, int height) { 37 .....//此處省略設(shè)置攝像機(jī)的代碼,將在后面詳細(xì)介紹 38 } 39 public void onSurfaceCreated(GL10 gl, EGLConfig config) { 40 .....//此處省略初始化的代碼,將在后面詳細(xì)介紹 41 } 42 public int initTexture(Resources res,String pname)//textureId{ 43 .....//此處省略加載紋理的代碼,將在后面詳細(xì)介紹 44 }}第1~9行為聲明包名,其中部分類和包的導(dǎo)入代碼、相關(guān)成員變量的聲明代碼在此處省略,請(qǐng)讀者自行查閱隨書附帶的光盤代碼;然后創(chuàng)建構(gòu)造方法,獲取父類上下文對(duì)象,設(shè)置使用OPENGL ES2.0渲染技術(shù)進(jìn)行繪制。
第11~18行首先清除深度緩沖與顏色緩沖,進(jìn)行現(xiàn)場(chǎng)保護(hù),判斷背景、魚食、單條魚、烏龜以及魚群的引用若不為空,依次繪制背景圖、魚食、單條魚、烏龜以及魚群。這里只給出了黃色小丑魚群的繪制代碼,其他魚群繪制代碼與之相似,請(qǐng)讀者自行查閱隨書附帶光盤的源代碼。
第19~27行為繪制珍珠貝的代碼。首先保護(hù)現(xiàn)場(chǎng),然后平移到指定位置,繪制珍珠貝,恢復(fù)現(xiàn)場(chǎng)。并且不斷更新動(dòng)畫播放時(shí)間,若當(dāng)前播放時(shí)間大于總的動(dòng)畫時(shí)間,則實(shí)際播放時(shí)間等于當(dāng)前播放時(shí)間減去總的動(dòng)畫時(shí)間。
第28~34行為繪制氣泡的代碼。首先開啟混合,設(shè)置混合因子,保護(hù)現(xiàn)場(chǎng),判斷氣泡引用不為空,則進(jìn)行氣泡的繪制,然后恢復(fù)現(xiàn)場(chǎng),關(guān)閉混合。
(2)下面介紹上面省略的onSurfaceChanged方法。重寫該方法,主要作用是設(shè)置視口的大小及位置、計(jì)算GLSurfaceView的寬高比、通過計(jì)算產(chǎn)生投影矩陣以及攝像機(jī)9參數(shù)位置矩陣。該方法是場(chǎng)景渲染器類不可或缺的。具體代碼如下所示。
第1~10行用于設(shè)置視窗大小及位置,獲取屏幕高度以及寬度,設(shè)置視角的left值以及top值,計(jì)算橫屏豎屏縮放比,產(chǎn)生透視投影矩陣。這里使用透視投影矩陣是為了更真實(shí)地模擬現(xiàn)實(shí)世界,產(chǎn)生近大遠(yuǎn)小的效果。
第11~20行用于產(chǎn)生攝像機(jī)的9參數(shù)位置矩陣,分別設(shè)置攝像機(jī)的XYZ位置、觀測(cè)點(diǎn)的XYZ位置以及up向量的XYZ分量,這里將攝像機(jī)位置矩陣的9參數(shù)都存放在Constant類中,是為了便于壁紙左右移動(dòng)時(shí)修改攝像機(jī)的位置。
(3)下面介紹上面省略的onSurfaceCreated方法。重寫該方法,主要作用是初始化光源位置,創(chuàng)建紋理管理器,加載紋理,獲取ms3d文件的輸入流,加載ms3d模型,創(chuàng)建魚類、烏龜、珍珠貝等對(duì)象,開啟深度檢測(cè)等。具體代碼如下所示。
第1~6行為設(shè)置背景色的RGBA通道,初始化矩陣,只有初始化矩陣之后,保護(hù)矩陣、恢復(fù)矩陣等才能起作用。初始化光源位置,將光源置于場(chǎng)景的正上方。創(chuàng)建紋理管理器對(duì)象,用于加載紋理圖,并且加載呈現(xiàn)明暗效果的紋理圖。
第7~23行為獲取ms3d文件的輸入流,從輸入流中加載ms3d模型,向魚類列表中添加單條魚、烏龜?shù)取_@里僅給出了fish0的加載代碼,其他種類魚、烏龜以及珍珠貝的加載代碼與此相似,故省略,請(qǐng)讀者自行查閱隨書附帶光盤的源代碼。
第24~42行為加載背景、魚食以及氣泡的紋理,打開深度檢測(cè),創(chuàng)建背景、氣泡、魚食、喂食、魚類以及魚群的對(duì)象。其中在創(chuàng)建魚群對(duì)象時(shí),只給出了創(chuàng)建黃色小丑魚魚群的代碼,其他魚群的創(chuàng)建代碼與此相似,故省略,請(qǐng)讀者自行查閱隨書附帶光盤的源代碼。
(4)下面詳細(xì)介紹上面省略的initTexture方法。該方法的主要作用是通過輸入流從assets中加載圖片,生成紋理ID,設(shè)置紋理的拉伸方式,設(shè)置紋理采樣方式等。具體代碼如下所示。
第2~17行為定義紋理ID、生成紋理ID數(shù)組、以及綁定紋理。同時(shí)設(shè)置紋理的過濾方式分別為最近點(diǎn)采樣過濾和線性紋理過濾,設(shè)置紋理的拉伸方式為縱向拉伸方式和橫向拉伸方式并且都為重復(fù)拉伸方式。
第18~33行為創(chuàng)建輸入流,從assets中加載紋理圖片,創(chuàng)建Bitmap對(duì)象,對(duì)獲取的圖片進(jìn)行解碼,然后關(guān)閉輸入流。其中關(guān)閉輸入流是非常重要的,加載完圖片,一定要記得關(guān)閉輸入流,否則會(huì)造成資源浪費(fèi)。
第34~41行為指定紋理。首先是紋理類型,在OpenGL ES中必須為GLES20.GL_ TEXTURE_2D;其次是紋理的層次,0表示基本圖像層,可以理解為直接貼圖;然后是紋理的圖像以及邊框尺寸;最后釋放Bitmap,返回紋理ID。
總結(jié)
以上是生活随笔為你收集整理的《Android 应用案例开发大全(第3版)》——第2.4节壁纸的实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: electron 窗口BrowserWi
- 下一篇: 《Android 应用案例开发大全(第二