日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

《Android 应用案例开发大全(第3版)》——第2.4节壁纸的实现

發(fā)布時間:2024/3/26 Android 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《Android 应用案例开发大全(第3版)》——第2.4节壁纸的实现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本節(jié)書摘來自異步社區(qū)《Android 應(yīng)用案例開發(fā)大全(第3版)》一書中的第2章,第2.4節(jié)壁紙的實現(xiàn),作者 吳亞峰 , 蘇亞光 , 于復(fù)興,更多章節(jié)內(nèi)容可以訪問云棲社區(qū)“異步社區(qū)”公眾號查看

2.4 壁紙的實現(xiàn)
上一節(jié)介紹了壁紙的框架,讓讀者對3D動態(tài)壁紙的整體框架有了初步認識,本節(jié)將要對動態(tài)壁紙的實現(xiàn)服務(wù)類GLWallpaperService和OpenGLES2WallpaperService以及自定義場景渲染器類MySurfaceView的開發(fā)進行詳細介紹。

2.4.1 壁紙服務(wù)類——OpenGLES2WallpaperService
這兩個類是本項目中最基礎(chǔ)的類,沒有這兩個類就不可能使用壁紙。GLWallpaperService類為開發(fā)人員提供了壁紙服務(wù),OpenGLES2WallpaperService通過繼承GLWallpaperService類,重寫此類中的方法來實現(xiàn)壁紙的后續(xù)開發(fā)。下面著重介紹一下OpenGLES2WallpaperService類中的onCreate方法和GLWallpaperService類中的觸控響應(yīng)事件onTouchEvent。

(1)首先是OpenGLES2WallpaperService類中的onCreate方法,onCreate方法是OpenGLES2 WallpaperService類的核心部分,其中包括獲取當前手機的配置信息,并且判斷其是否支持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 = //獲取當前機器配置信息 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管理器,獲取配置信息,判斷當前手機是否支持OPENGL ES2.0渲染技術(shù),并將結(jié)果存儲在supportsEs2中。
第9~13行用于判斷supportsEs2中的值,如果當前手機支持OPENGL ES2.0渲染技術(shù),則設(shè)置使用OPENGL ES2.0進行繪制,并且讓EGL跨越暫停或恢復(fù)界限來嘗試和保護環(huán)境,然后設(shè)置場景渲染器;如果不支持OPENGL ES2.0,則退出繪制。
(2)下面將對屏幕觸控的響應(yīng)事件進行介紹。屏幕的觸控事件分為3部分:第一部分是滑動屏幕使背景圖跟著屏幕左右移動,第二部分是點擊屏幕下方修改標志位,最后一部分是手指抬起時判斷是否進行喂食,具體代碼如下所示。

1 private float mPreviousY; //上次的觸控位置Y坐標 2 private float mPreviousX; //上次的觸控位置X坐標 3 @Override 4 public void onTouchEvent(MotionEvent e) { 5 float y = e.getY(); //獲取觸控點Y坐標 6 float x = e.getX(); //獲取觸控點X坐標 7 switch (e.getAction()) { 8 case MotionEvent.ACTION_DOWN: 9 Constant.feeding=true;break; //喂食標志位設(shè)為true 10 case MotionEvent.ACTION_MOVE: 11 float dy = y - mPreviousY; //計算觸控筆Y位移 12 float dx = x - mPreviousX; //計算觸控筆X位移 13 if (dx < 0){ //摸左邊x為正,摸右邊x為負 14 if (Constant.CameraX <Constant.MaxCameraMove) { //判斷是否超出移動范圍 15 if(dx<-Constant.Thold){ Constant.feeding = false; }//喂食標志位置為false 16 Constant.CameraX = Constant.CameraX - dx / Constant.CameraMove_SCALE ; 17 Constant.TargetX=Constant.CameraX; //移動攝像機的坐標 18 }} else { 19 if (Constant.CameraX >-Constant.MaxCameraMove) { //判斷是否超出移動范圍 20 if(dx>Constant.Thold){ Constant.feeding =false;} //喂食標志位置為false 21 Constant.CameraX = Constant.CameraX - dx / Constant.CameraMove_SCALE ; 22 Constant.TargetX=Constant.CameraX; //移動攝像機的坐標 23 }} 24 MatrixState.setCamera( //將攝像機的位置信息存入到矩陣中 25 Constant.CameraX, Constant.CameraY, Constant.CameraZ,//攝像機的X、Y、Z位置 26 Constant.TargetX, Constant.TargetY, Constant.TargetZ,//觀測點的X、Y、Z位置 27 Constant.UpX, Constant.UpY, Constant.UpZ); //up向量的X、Y、Z分量 28 break; 29 case MotionEvent.ACTION_UP: 30 if (Constant.feeding) { //標志位,開始喂食 31 if (Constant.isFeed) { 32 Constant.isFeed = false; //把標志位置為false 33 float[] AB = IntersectantUtil.calculateABPosition( //通過矩陣變換獲取世界坐標系中的點 34 x, y, //觸控點X、Y坐標 35 Constant.SCREEN_WIDTH, Constant.SCREEN_HEGHT, //屏幕寬、長度 36 Constant.leftABS, Constant.topABS, //視角left、top值 37 Constant.nearABS, Constant.farABS); //視角near、far值 38 Vector Start = new Vector(AB[0], AB[1], AB[2]); //起點 39 Vector End = new Vector(AB[3], AB[4], AB[5]); //終點 40 if (MySurfaceView.feedfish != null) { //判斷不為空啟動 41 MySurfaceView.feedfish.startFeed(Start, End); //開始喂食 42 }}} 43 break; 44 } 45 mPreviousY = y; //記錄觸控筆Y位置 46 mPreviousX = x; //記錄觸控筆X位置 47 super.onTouchEvent(e); 48 }

第1~9行首先創(chuàng)建變量,用于記錄觸控筆上一次的觸控X位置和Y位置,然后獲取當前觸控點的X坐標和Y坐標,并且響應(yīng)屏幕的觸控事件,對ACTION_DOWN事件進行監(jiān)聽,當觸發(fā)時將喂食標志位設(shè)為true。
第10~28行對ACTION_MOVE事件進行監(jiān)聽,獲取手指在屏幕上的移動距離,按照一定比例移動攝像機X坐標,同時,如果攝像機X坐標達到閾值,則攝像機不會向滑動方向移動;然后將攝像機的位置信息存入到矩陣中,設(shè)置攝像機的位置,觀測點的坐標和up向量。
第30~37行是判斷喂食的標志位,因為滑動屏幕不能喂食,當前喂的食物在沒有消失之前也不能喂食,所以需要兩個標志位對其進行控制。一個在點擊喂食的時候為true,另一個在沒有喂食之前為true,然后通過矩陣變換獲取觸控點在世界坐標系中的坐標。
第38~47行通過拾取計算獲取觸控點在世界坐標系中的起點(近平面點)坐標、終點(遠平面點)坐標,判斷feedfish不為空,則調(diào)用startFeed方法開始喂食;然后記錄觸控筆的X位置、Y位置,回調(diào)父類的方法。

2.4.2 自定義渲染器類——MySurfaceView
下面將詳細介紹自定義的場景渲染器代碼,在自定義的場景渲染器類里,可以進行魚、魚群、烏龜、珍珠貝、氣泡、背景圖、魚食的初始化。初始化魚類和烏龜?shù)某跏妓俣取⒊跏嘉恢靡约凹虞d紋理等,并且設(shè)置光源位置,初始化矩陣等。

(1)由于MySurfaceView類中繪制代碼以及初始化代碼比較多,在此首先介紹該類的繪制代碼以及整體框架,使讀者對此類有一個大致的了解。具體代碼如下所示。

1 package wyf.lxg.mywallpaper; 2 .....//此處省略部分類和包的導(dǎo)入代碼,請讀者自行查閱隨書附帶光盤的源代碼 3 public class MySurfaceView extends GLSurfaceView 4 implements GLSurfaceView.Renderer,OpenGLES2WallpaperService.Renderer { 5 public MySurfaceView(Context context) { 6 super(context); //獲取上下文對象 7 this.setEGLContextClientVersion(2); //設(shè)置使用OPENGL ES2.0 8 } 9 .....//此處省略相關(guān)成員變量的聲明代碼,請讀者自行查閱隨書附帶光盤的源代碼 10 public void onDrawFrame(GL10 gl) { 11 GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT //清除深度緩沖與顏色緩沖 12 | GLES20.GL_COLOR_BUFFER_BIT); 13 MatrixState.pushMatrix(); //保護矩陣 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 .....//此處繪制其他魚群的代碼與上述相似,故省略,請讀者自行查閱隨書附帶光盤的源代碼 19 MatrixState.pushMatrix(); //保護矩陣 20 MatrixState.translate(,-16,); //平移到指定位置 21 this.haibei.animate(time,dpm); //繪制珍珠貝 22 MatrixState.popMatrix(); //恢復(fù)矩陣 23 time += ; 24 if(time > this.ms3d.getTotalTime()) { //若當前播放時間大于總的動畫時間 25 time = time - this.ms3d.getTotalTime();//則播放時間等于當前播放時間減去總的動畫時間 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(); //保護矩陣 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è)置攝像機的代碼,將在后面詳細介紹 38 } 39 public void onSurfaceCreated(GL10 gl, EGLConfig config) { 40 .....//此處省略初始化的代碼,將在后面詳細介紹 41 } 42 public int initTexture(Resources res,String pname)//textureId{ 43 .....//此處省略加載紋理的代碼,將在后面詳細介紹 44 }}

第1~9行為聲明包名,其中部分類和包的導(dǎo)入代碼、相關(guān)成員變量的聲明代碼在此處省略,請讀者自行查閱隨書附帶的光盤代碼;然后創(chuàng)建構(gòu)造方法,獲取父類上下文對象,設(shè)置使用OPENGL ES2.0渲染技術(shù)進行繪制。
第11~18行首先清除深度緩沖與顏色緩沖,進行現(xiàn)場保護,判斷背景、魚食、單條魚、烏龜以及魚群的引用若不為空,依次繪制背景圖、魚食、單條魚、烏龜以及魚群。這里只給出了黃色小丑魚群的繪制代碼,其他魚群繪制代碼與之相似,請讀者自行查閱隨書附帶光盤的源代碼。
第19~27行為繪制珍珠貝的代碼。首先保護現(xiàn)場,然后平移到指定位置,繪制珍珠貝,恢復(fù)現(xiàn)場。并且不斷更新動畫播放時間,若當前播放時間大于總的動畫時間,則實際播放時間等于當前播放時間減去總的動畫時間。
第28~34行為繪制氣泡的代碼。首先開啟混合,設(shè)置混合因子,保護現(xiàn)場,判斷氣泡引用不為空,則進行氣泡的繪制,然后恢復(fù)現(xiàn)場,關(guān)閉混合。
(2)下面介紹上面省略的onSurfaceChanged方法。重寫該方法,主要作用是設(shè)置視口的大小及位置、計算GLSurfaceView的寬高比、通過計算產(chǎn)生投影矩陣以及攝像機9參數(shù)位置矩陣。該方法是場景渲染器類不可或缺的。具體代碼如下所示。

1 public void onSurfaceChanged(GL10 gl, int width, int height) { 2 GLES20.glViewport(0, 0, width, height); //設(shè)置視窗大小及位置 3 float ratio = (float) width / height; //計算GLSurfaceView的寬高比 4 Constant.SCREEN_HEGHT=height; //獲取屏幕高度 5 Constant.SCREEN_WIDTH=width; //獲取屏幕寬度 6 Constant.leftABS=ratio*Constant.View_SCALE; //設(shè)置left值 7 Constant.topABS=1 * Constant.View_SCALE; //設(shè)置top值 8 Constant.SCREEN_SCALEX=Constant.View_SCALE*((ratio>1)?ratio:(1/ratio)); //設(shè)置縮放比 9 MatrixState.setProjectFrustum(-Constant.leftABS, Constant.leftABS, //產(chǎn)生透視投影矩陣 10 -Constant.topABS, Constant.topABS, Constant.nearABS,Constant.farABS); 11 MatrixState.setCamera( //產(chǎn)生攝像機9參數(shù)位置矩陣 12 Constant.CameraX //攝像機的X位置 13 Constant.CameraY, //攝像機的Y位置 14 Constant.CameraZ, //攝像機的Z位置 15 Constant.TargetX, //觀測點的X位置 16 Constant.TargetY, //觀測點的Y位置 17 Constant.TargetZ, //觀測點的Z位置 18 Constant.UpX, //up向量的X分量 19 Constant.UpY, //up向量的Y分量 20 Constant.UpZ); //up向量的Z分量 21 }

第1~10行用于設(shè)置視窗大小及位置,獲取屏幕高度以及寬度,設(shè)置視角的left值以及top值,計算橫屏豎屏縮放比,產(chǎn)生透視投影矩陣。這里使用透視投影矩陣是為了更真實地模擬現(xiàn)實世界,產(chǎn)生近大遠小的效果。
第11~20行用于產(chǎn)生攝像機的9參數(shù)位置矩陣,分別設(shè)置攝像機的XYZ位置、觀測點的XYZ位置以及up向量的XYZ分量,這里將攝像機位置矩陣的9參數(shù)都存放在Constant類中,是為了便于壁紙左右移動時修改攝像機的位置。
(3)下面介紹上面省略的onSurfaceCreated方法。重寫該方法,主要作用是初始化光源位置,創(chuàng)建紋理管理器,加載紋理,獲取ms3d文件的輸入流,加載ms3d模型,創(chuàng)建魚類、烏龜、珍珠貝等對象,開啟深度檢測等。具體代碼如下所示。

1 public void onSurfaceCreated(GL10 gl, EGLConfig config){ 2 GLES20.glClearColor(,,, ); //設(shè)置屏幕背景色RGBA 3 MatrixState.setInitStack(); //初始化矩陣 4 MatrixState.setLightLocation(0,9,13); //初始化光源位置 5 manager = new TextureManager(getResources()); //創(chuàng)建紋理管理器對象 6 dpm=initTexture(MySurfaceView.this.getResources(),"dpm.png");//加載明暗紋理 7 String name="ms3d/"; //獲取ms3d文件的輸入流 8 InputStream in=null; 9 ......//此處其他輸入流的聲明與上述相同,故省略,請讀者自行查閱隨書附帶光盤的源代碼 10 try{in=getResources().getAssets().open(name+"fish0.ms3d");//鰩魚 12 ......//此處其他獲取輸入流與上述相同,故省略,請讀者自行查閱隨書附帶光盤的源代碼 13 } catch(Exception e){ 14 e.printStackTrace(); //打印異常棧信息 15 } 16 ms3d = MS3DModel.load(in,manager,MySurfaceView.this); //從輸入流加載模型 17 ......//此處加載模型代碼與上述相同,故省略,請讀者自行查閱隨書附帶光盤的源代碼 18 if(fishAl.size() ){ 19 fishAl.add(new SingleFish(ms3d,dpm, //位置、速度、力、吸引力、重力 20 new Vector(-7, 5, -7), new Vector(, , ), 21 new Vector(0, 0, 0), new Vector(0, 0, 0), 150)); 22 .....//此處添加魚的代碼與上述相同,故省略,請讀者自行查閱隨書附帶光盤的源代碼 23 } 24 back=initTexture(MySurfaceView.this.getResources(),"background.png"); //背景紋理 25 fishfood=initTexture(MySurfaceView.this.getResources(),"fishfood.png"); //魚食紋理 26 bubbles=initTexture(MySurfaceView.this.getResources(),"bubble.png");//氣泡紋理 27 GLES20.glEnable(GLES20.GL_DEPTH_TEST); //打開深度檢測 28 bg=new Background(MySurfaceView.this); //創(chuàng)建背景對象 29 bubble = new BubbleControl(MySurfaceView.this,bubbles); //創(chuàng)建氣泡對象 30 fishfoods=LoadUtil.loadFromFile("fishfood.obj", //魚食對象 31 MySurfaceView.this.getResources(),MySurfaceView.this); 32 singlefood=new SingleFood(fishfood,fishfoods, MySurfaceView.this);//單個魚食對象 33 feedfish=new FeedFish(MySurfaceView.this); //喂食 34 if (fishControl == null) { //創(chuàng)建對象魚類的Control對象 35 fishControl = new FishControl(fishAl, MySurfaceView.this); 36 } 37 if (fishSchool == null) { //創(chuàng)建魚群對象的Control 38 fishSchool = new FishSchoolControl(ms3d3,dpm,MySurfaceView.this, 39 new Vector(5, -2, 4),new Vector(, , ),50);//位置、速度、質(zhì)量 40 } 41 ......//此處添加魚群的代碼與上述相同,故省略,請讀者自行查閱隨書附帶光盤的源代碼 42 GLES20.glDisable(GLES20.GL_CULL_FACE); //關(guān)閉背面剪裁 43 }

第1~6行為設(shè)置背景色的RGBA通道,初始化矩陣,只有初始化矩陣之后,保護矩陣、恢復(fù)矩陣等才能起作用。初始化光源位置,將光源置于場景的正上方。創(chuàng)建紋理管理器對象,用于加載紋理圖,并且加載呈現(xiàn)明暗效果的紋理圖。
第7~23行為獲取ms3d文件的輸入流,從輸入流中加載ms3d模型,向魚類列表中添加單條魚、烏龜?shù)取_@里僅給出了fish0的加載代碼,其他種類魚、烏龜以及珍珠貝的加載代碼與此相似,故省略,請讀者自行查閱隨書附帶光盤的源代碼。
第24~42行為加載背景、魚食以及氣泡的紋理,打開深度檢測,創(chuàng)建背景、氣泡、魚食、喂食、魚類以及魚群的對象。其中在創(chuàng)建魚群對象時,只給出了創(chuàng)建黃色小丑魚魚群的代碼,其他魚群的創(chuàng)建代碼與此相似,故省略,請讀者自行查閱隨書附帶光盤的源代碼。
(4)下面詳細介紹上面省略的initTexture方法。該方法的主要作用是通過輸入流從assets中加載圖片,生成紋理ID,設(shè)置紋理的拉伸方式,設(shè)置紋理采樣方式等。具體代碼如下所示。

1 public int initTexture(Resources res,String pname){ //初始化紋理 2 int[] textures = new int[1]; //生成紋理ID 3 GLES20.glGenTextures( 4 1, //產(chǎn)生的紋理id的數(shù)量 5 textures, //紋理id的數(shù)組 6 0 //偏移量 7 ); 8 int textureId=textures[0]; 9 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);//綁定紋理 10 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, //最近點采樣 11 GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST); 12 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, //線性紋理過濾 13 GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR); 14 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, //縱向拉伸方式 15 GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_REPEAT); 16 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, //橫向拉伸方式 17 GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_REPEAT); 18 InputStream is = null; //創(chuàng)建輸入流 19 String name="pic/"+pname; 20 try { 21 is = res.getAssets().open(name); //加載紋理圖片 22 } catch (IOException e1) { 23 e1.printStackTrace(); //異常處理 24 } 25 Bitmap bitmapTmp; //創(chuàng)建Bitmap對象 26 try { 27 bitmapTmp = BitmapFactory.decodeStream(is); //對獲取的圖片解碼 28 } finally { 29 try { 30 is.close(); //關(guān)閉輸入流 31 }catch(IOException e) { 32 e.printStackTrace(); //異常處理 33 }} 34 GLUtils.texImage2D( 35 GLES20.GL_TEXTURE_2D, //紋理類型 36 0, //紋理的層次 37 bitmapTmp, //紋理圖像 38 0 //紋理邊框尺寸 39 ); 40 bitmapTmp.recycle(); //釋放Bitmap 41 return textureId; 42 }

第2~17行為定義紋理ID、生成紋理ID數(shù)組、以及綁定紋理。同時設(shè)置紋理的過濾方式分別為最近點采樣過濾和線性紋理過濾,設(shè)置紋理的拉伸方式為縱向拉伸方式和橫向拉伸方式并且都為重復(fù)拉伸方式。
第18~33行為創(chuàng)建輸入流,從assets中加載紋理圖片,創(chuàng)建Bitmap對象,對獲取的圖片進行解碼,然后關(guān)閉輸入流。其中關(guān)閉輸入流是非常重要的,加載完圖片,一定要記得關(guān)閉輸入流,否則會造成資源浪費。
第34~41行為指定紋理。首先是紋理類型,在OpenGL ES中必須為GLES20.GL_ TEXTURE_2D;其次是紋理的層次,0表示基本圖像層,可以理解為直接貼圖;然后是紋理的圖像以及邊框尺寸;最后釋放Bitmap,返回紋理ID。

總結(jié)

以上是生活随笔為你收集整理的《Android 应用案例开发大全(第3版)》——第2.4节壁纸的实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。