Android源碼之動態壁紙引擎


動態壁紙蠻好玩的,也沒接觸過,看官方有就拿了學習下,是第一次接觸引擎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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM