動態壁紙蠻好玩的,也沒接觸過,看官方有就拿了學習下,是第一次接觸引擎Engine,激動興奮...效果做出來了,記錄筆記,吼吼,跟大家交流學習, 廢話不多說了,先看效果,再看源碼,供大家交流學習,今天的效果如下圖所示,因為手機開機后就要加載圖片,所以就直接從開機啟動完成后講了,看圖...
未開鎖時立方體形式一:
開鎖時立方體形式一與二:
簡單的繪制效果,因為立方體都是下面這些圖(由三角形拼成的)拼的,所以此處貼下這個效果圖,效果制作的代碼我放在形式一注釋里面了,大家可以試下的,就是這個效果,臨時引用的:
工程結構如下圖所示:
因為形式一與形式二只是繪制點不一樣,兩個類都一樣,防止篇幅過長(51有限制,超過80000字符就掛了,我已經超過了,這是第二邊寫了,所以形式二代碼就不貼了),小馬就直接貼形式一的代碼與配置文件代碼,詳細的如有朋友要學習的話,下載下DEMO學習就是,小馬基本的注釋都加了,因為也在學習階段,如有地方不足的,希望大家直接留言,批評指出,小馬肯定感謝...
立方體形式一控制類代碼:
package xiaoma.cube1; import android.graphics.Canvas; import android.graphics.Paint; import android.os.Handler; import android.os.SystemClock; import android.service.wallpaper.WallpaperService; import android.view.MotionEvent; import android.view.SurfaceHolder; /** * @Title: CubeWallpaper1.java * @Package cube1 * @Description: 初識Android動態壁紙引擎 * @author XiaoMa */ /* * 因為小馬沒接觸過引擎,也無從下手學習,今天就拿官方的例子來試試刀了, * 吼吼,剛開始不知道,看了下代碼,里面有講到WallPaperService * 查詢這個服務可以查到與之相關聯的類與方法,如下面官方文檔中講的,大家 * 英語不好也可以用工具看個大概,英語不好的朋友記得多用工具學習下,小馬 * 英語也不咋的.... * A wallpaper service is responsible for showing a live wallpaper behind * applications that would like to sit on top of it. This service object itself * does very little -- its only purpose is to generate instances of * WallpaperService.Engine as needed. Implementing a wallpaper thus involves * subclassing from this, subclassing an Engine implementation, and implementing * onCreateEngine() to return a new instance of your engine * 上面講的大體是:一個類必須是WallpaperService引擎類的子類,而且里面必須重寫 * onCreateEngine這個方法,要仔細看的話小馬也看不懂英文,照着例子,看官方文檔, * 多猜多用工具查就行了,小馬英語爛的可以讓你吐血...我能看懂,你肯定能看懂 */ public class CubeWallpaper1 extends WallpaperService { /*常用的都是這樣的,用一個handler來動態的去刷新UI,對吧?猜的,看下面代碼到底是不是*/ private final Handler mHandler = new Handler(); /** * 這個方法與Activity里面的一樣,當這個類的服務被第一次創建時 * 調用,也就是說,這個方法只調用一次.. */ @Override public void onCreate() { super.onCreate(); } /** * 與上面反的,銷毀時調用,這個猜下, * 不懂了查文檔 */ @Override public void onDestroy() { super.onDestroy(); } /** * 這個方法在類注釋中寫明了 * implementing onCreateEngine() to return a new instance of your engine * 必須實現這個方法來返回我們自己定義引擎的一個實例 */ @Override public Engine onCreateEngine() { return new CubeEngine(); } /** * * @Title: CubeWallpaper1.java * @Package cube1 * @Description: 自定義引擎類 * @author XiaoMa */ class CubeEngine extends Engine { private final Paint mPaint = new Paint(); private float mOffset; /*用戶觸摸位置*/ private float mTouchX = -1; private float mTouchY = -1; private long mStartTime; /*屏幕中心坐標,記下,是中心不是原心(0,0)*/ private float mCenterX; private float mCenterY; private final Runnable mDrawCube = new Runnable() { public void run() { drawFrame(); } }; private boolean mVisible; CubeEngine() { /*下面這幾行就為了在屏幕中畫立方體的線條而做准備*/ final Paint paint = mPaint; paint.setColor(0xffffffff);//畫筆顏色 paint.setAntiAlias(true);//抗鋸齒 paint.setStrokeWidth(2);//線條粗細,猜的,不知道對不對 paint.setStrokeCap(Paint.Cap.ROUND); paint.setStyle(Paint.Style.STROKE); //系統啟動完之后,開始繪制壁紙的時間,這個時間里面包含有系統睡眠時間 mStartTime = SystemClock.elapsedRealtime(); } /** * 大家發現這個onCreate與Activity的方法有什么不同了吧? * 老規矩的,還是在初始化壁紙引擎的時候調用這個方法,並設置觸 * 屏事件為可用 */ @Override public void onCreate(SurfaceHolder surfaceHolder) { super.onCreate(surfaceHolder); setTouchEventsEnabled(true); } @Override public void onDestroy() { super.onDestroy(); mHandler.removeCallbacks(mDrawCube); } /** * 系統壁紙狀態改變時會調用這個方法,如: * 壁紙由隱藏轉換為顯示狀態時會調用這個方法 */ @Override public void onVisibilityChanged(boolean visible) { mVisible = visible; /*下面這個判斷好玩,就是說,如果屏幕壁紙狀態轉為顯式時重新繪制壁紙,否則黑屏幕,隱藏就可以*/ if (visible) { drawFrame(); } else { mHandler.removeCallbacks(mDrawCube); } } @Override public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { super.onSurfaceChanged(holder, format, width, height); //下面是來保存屏幕顯示立方體的,也就是你能看到的正面圖的中心位置 mCenterX = width / 2.0f; mCenterY = height / 2.0f; drawFrame(); } /** * 下面兩個方法是為了方便調用SurfaceHolder交互來重寫的 */ @Override public void onSurfaceCreated(SurfaceHolder holder) { super.onSurfaceCreated(holder); } @Override public void onSurfaceDestroyed(SurfaceHolder holder) { super.onSurfaceDestroyed(holder); mVisible = false; mHandler.removeCallbacks(mDrawCube); } /** * 當手動壁紙時根據偏移量重繪壁紙 */ @Override public void onOffsetsChanged(float xOffset, float yOffset, float xStep, float yStep, int xPixels, int yPixels) { mOffset = xOffset; drawFrame(); } /* * 在這個地方保存觸摸的位置,我們會在繪制壁紙的時候使用觸摸值 */ @Override public void onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_MOVE) { mTouchX = event.getX(); mTouchY = event.getY(); } else { mTouchX = -1; mTouchY = -1; } super.onTouchEvent(event); } /* * 繪制立方體方法實現 */ void drawFrame() { final SurfaceHolder holder = getSurfaceHolder(); Canvas c = null; try { c = holder.lockCanvas(); if (c != null) { drawCube(c); drawTouchPoint(c); } } finally { if (c != null) holder.unlockCanvasAndPost(c); } // 在指定時間里重繪制,這個地方大家可以看效果圖,如果你拖動過快的話,立方體 //每個頂點之間會有一個短暫的未連接延遲,就是在這個地方使用了延遲來繪制的 mHandler.removeCallbacks(mDrawCube); if (mVisible) { mHandler.postDelayed(mDrawCube, 1000 / 25); } } /* * 這個地方是以立方體某個頂點為起始端,繪制三條線 * 一堆數字,看着好暈 * 在這小馬順便貼在這個DEMO里面用到的基本的繪制,如下: * graphics.Canvas有四種畫矩形的方法。 canvas.drawRect(new RectF(10, 10, 300, 100), paint); canvas.drawRect(10, 150, 300, 200, paint); canvas.drawRect(new Rect(10, 250, 300, 300), paint); 第四種:畫圓角的矩形 canvas.drawRoundRect(new RectF(10, 350, 300, 450), 10, 10, paint); 第二個和第三個參數為圓角的寬高。 有興趣的朋友可以改下下面這些東西 */ void drawCube(Canvas c) { c.save(); c.translate(mCenterX, mCenterY); c.drawColor(0xff000000); drawLine(c, -400, -400, -400, 400, -400, -400); drawLine(c, 400, -400, -400, 400, 400, -400); drawLine(c, 400, 400, -400, -400, 400, -400); drawLine(c, -400, 400, -400, -400, -400, -400); drawLine(c, -400, -400, 400, 400, -400, 400); drawLine(c, 400, -400, 400, 400, 400, 400); drawLine(c, 400, 400, 400, -400, 400, 400); drawLine(c, -400, 400, 400, -400, -400, 400); drawLine(c, -400, -400, 400, -400, -400, -400); drawLine(c, 400, -400, 400, 400, -400, -400); drawLine(c, 400, 400, 400, 400, 400, -400); drawLine(c, -400, 400, 400, -400, 400, -400); c.restore(); } /* * 在屏幕中繪制三維空間的線 */ void drawLine(Canvas c, int x1, int y1, int z1, int x2, int y2, int z2) { /* *因為大家都知道,壁紙是手機啟動完成之后就已經開始繪制的,一般取時間什么的 *我們都用Timer System.currentTimeMillis() Calendar來取 *這個地方取系統級啟動時間等的,記住這個類,SystemClock,方法自己查 */ long now = SystemClock.elapsedRealtime(); /*取得三維坐標軸的旋轉值*/ float xrot = ((float) (now - mStartTime)) / 1000; float yrot = (0.5f - mOffset) * 2.0f; float zrot = 0; // rotation around X-axis ??? float newy1 = (float) (Math.sin(xrot) * z1 + Math.cos(xrot) * y1); float newy2 = (float) (Math.sin(xrot) * z2 + Math.cos(xrot) * y2); float newz1 = (float) (Math.cos(xrot) * z1 - Math.sin(xrot) * y1); float newz2 = (float) (Math.cos(xrot) * z2 - Math.sin(xrot) * y2); // rotation around Y-axis ??? float newx1 = (float) (Math.sin(yrot) * newz1 + Math.cos(yrot) * x1); float newx2 = (float) (Math.sin(yrot) * newz2 + Math.cos(yrot) * x2); newz1 = (float) (Math.cos(yrot) * newz1 - Math.sin(yrot) * x1); newz2 = (float) (Math.cos(yrot) * newz2 - Math.sin(yrot) * x2); // 3D-to-2D projection ??? float startX = newx1 / (4 - newz1 / 400); float startY = newy1 / (4 - newz1 / 400); float stopX = newx2 / (4 - newz2 / 400); float stopY = newy2 / (4 - newz2 / 400); c.drawLine(startX, startY, stopX, stopY, mPaint); } /* * 按位屏幕手動時繪制一個白色的圈 */ void drawTouchPoint(Canvas c) { if (mTouchX >= 0 && mTouchY >= 0) { c.drawCircle(mTouchX, mTouchY, 80, mPaint); } } } }
配置文件代碼如下:
package="xiaoma.cube1" android:versionCode="1" android:versionName="1.0" > android:label="@string/wallpapers" android:icon="@drawable/ic_launcher"> android:label="@string/wallpaper_cube1" android:name=".CubeWallpaper1" android:permission="android.permission.BIND_WALLPAPER"> android:label="@string/wallpaper_cube2" android:name=".CubeWallpaper2" android:permission="android.permission.BIND_WALLPAPER"> android:label="@string/cube2_settings" android:name=".CubeWallpaper2Settings" android:theme="@android:style/Theme.Light.WallpaperSettings" android:exported="true">
下載地址:http://www.eoeandroid.com/thread-178842-1-1.html