Android 动态壁纸原理 及 例子

  • Post author:
  • Post category:其他


最近做动态壁纸的项目,原来觉得动态壁纸是个很小的项目,但是看到Android Market上有个专门的动态壁纸分类(现在升级为Google Play了), 而且自己做的这个项目可连接上服务器,供用户购买下载图片,终于有了自信,认识到这个不算是个小项目了。接下来我主要谈谈动态壁纸的原理,然后会解释一个 “小球的例子”,供大家能深入的理解该原理。

一:原理

动态壁纸为:在手机上点击 Menu→Wallpapers→Live wallpapers→然后打开自己的程序。建个最简单的动态壁纸的步骤如下:

1.在rex/xml中新建一个.xml.其中注册一个wallpaper.假设这个名字为

ab.xml

(下文要用到,可随意设置,没要求)

最简单的就是写 这一句,这样的话打开动态壁纸就会出现只出现一个按钮(左图),一般我们不这样做,要像右图这样子。

Android 动态壁纸原理 及 例子
Android 动态壁纸原理 及 例子

若动态壁纸”设置…”(Setting…)你想连接Activity,也在这里指定,比如:

android:settingsActivity=”com.birbeck.wallpaperslideshow.SettingsActivity” (这个一般是继承了PreferenceActivity类的Activity。就是首选项模式的类),要设置了这个属性,就会如有图所示了。

Android 动态壁纸原理 及 例子

如上截图是手机上的动态壁纸列表,你也可以通过android:description=“XXX”来设置描述,通过anroid:thumbnail=”XX”来设置该动态壁纸的图片。

2.接下来要在manifest中注册一个service。

XXX

在这个servier中要指定你继承WallpaperService类的路径,指定1中设置的xml,设置广播,设置允许权限等。比如:

通过android:name=”com.bn.ex12f.Sample12_6_WallPaper”指定继承WallpaperService的类 ,

通过android:permission=”android.permission.BIND_WALLPAPER”>允许动态壁纸权限。

这一种还必须设置一个,用来监听Android系统发出的动态壁纸的广播。

还要通过ab” />.这篇文章中主要讲原理和重要的点,源码我会附上的。

3.就是实现继承了WallpaerService的类了。只需要重写WallpaperServiced的onCreateEngine方法。

@Override

public Engine onCreateEngine()

{


ce=new BallEngine();(class BallEngine extends Engine{…})

return ce;

}

在这个方法里只需返回一个Engine的子类对象就可以了。所以重头戏,写动态壁纸程序的

主要工作量

就是实现Engine的子类。

4.实现Engine的子类

简而言之,该类的作用就是让你去实现动态壁纸的具体代码。以上三点可认为是格式化的一些东西。这个类不需要强制继承任何方法,现在简述一下一般要重写的方法的功能。

public void onCreate(SurfaceHolder surfaceHolder){…}

public void onDestroy(){…}这俩方法就不说明了

public void onVisibilityChanged(boolean visible)

{


if(visible)//如果可见

{




}

else//如果不可见

{



}

}该方法作用是当前动态壁纸可见时要画图。重写这个方法一般如以上格式所示。

public void onSurfaceCreated(SurfaceHolder holder) //重写onSurfaceCreated方法

{


super.onSurfaceCreated(holder);//调用父类对应方法

}该方法是应用程序第一次创建时要调用。可在这个方法里调用父类对应方法。该方法执行完毕后系统会立即调用onSurfaceChanged方法(如下)。若在这里调用父类对应方法,那么就在onSurfaceChanged中实现主要功能。

public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height)

{

}该方法有两个用处。1.若动态壁纸要随着横屏竖屏而切换可在这里写。2.想和用户交互的话,比如用户滑动屏幕时,点击屏幕时等。3.注意:onSurfaceCreated调用之后会立即调用该方法。

这些就是动态壁纸原理的介绍。接下来是一个小例,希望大家能够喜欢。这个例子很简单。效果图如下:

功能说明:黄 蓝 绿三个小球(截图不好,球显示不对)。碰到屏幕边的话会像谈到地面上一样,会返回。

效果不错吧,你们会了吗? (代码虽然都附上了,但是资源,布局都没法附。博客园又不支持附件,还用原来的方法,想要代码,邮箱联系我:carman_loneliness@163.com )

Android 动态壁纸原理 及 例子

这个是继承了WallpaerService的类的代码。


001

package


com.bn.ex12f;

002

003

import


android.graphics.Bitmap;

004

import


android.graphics.BitmapFactory;

005

import


android.graphics.Canvas;

006

import


android.graphics.Color;

007

import


android.graphics.Paint;

008

import


android.os.Handler;

009

import


android.service.wallpaper.WallpaperService;

010

import


android.view.SurfaceHolder;

011

012

public


class


Sample12_6_WallPaper


extends


WallpaperService

013

{


014



BallEngine ce;


//BallEngine的引用

015



Handler hd =


new


Handler();


//创建Handler对象

016



Bitmap yellowBallBitmap;


//黄球位图

017



Bitmap blueBallBitmap;


//蓝球位图

018



Bitmap greenBallBitmap;


//绿球位图

019



@Override

020



public


Engine onCreateEngine()


//重写onCreateEngine方法

021



{


022



ce=


new


BallEngine();


//创建 BallEngine对象

023



return


ce;


//返回创建的对象

024



}

025



//初始化图片资源的方法

026



public


void


initBitmap(){


027



yellowBallBitmap=BitmapFactory.decodeResource(


this


.getResources(), R.drawable.yellowball);


//初始化黄球

028



blueBallBitmap=BitmapFactory.decodeResource(


this


.getResources(), R.drawable.blueball);


//初始化蓝球

029



greenBallBitmap=BitmapFactory.decodeResource(


this


.getResources(), R.drawable.greenball);


//初始化绿球

030



}

031



class


BallEngine


extends


Engine


//创建内部类

032



{


033



Sample12_6_WallPaper father;


//MovingBallWallPaper的引用

034



private


final


Paint paint =


new


Paint();


//创建画笔

035



boolean


ifDraw;


//是否可见的标志位

036



BallGoThread bgThread;


//BallGoThread引用

037



AllBalls allBalls;


// AllBalls对象的引用

038



private


final


Runnable mDrawCube =


new


Runnable() {



//匿名内部类

039



public


void


run() {



//重写run方法

040



drawBalls();


//调用drawBalls方法

041



}

042



};

043



@Override

044



public


void


onCreate(SurfaceHolder surfaceHolder)


//重写onCreate方法

045



{


046



super


.onCreate(surfaceHolder);


//调用父类对应方法

047



paint.setAntiAlias(


true


);


//打开抗锯齿

048



initBitmap();


//初始化位图资源

049



}

050

051



@Override

052



public


void


onDestroy()


//重写onDestroy方法

053



{


054



super


.onDestroy();


//调用父类对应方法

055



}

056

057



@Override

058



public


void


onVisibilityChanged(


boolean


visible)


//重写onVisibilityChanged方法

059



{


060



ifDraw=visible;


//获得是否可见标志位

061



if


(ifDraw)


//如果可见

062



{


063



bgThread=


new


BallGoThread(allBalls);


//创建BallGoThread线程

064



bgThread.start();


//启动该线程

065



hd.postDelayed(mDrawCube, Constant.MOVE_TIME);


//一定时间后绘制球

066



}

067



else


//如果不可见

068



{


069



bgThread.ballGoFlag=


false


;


//停止BallGoThread线程

070



}

071



}

072

073



@Override

074



public


void


onSurfaceChanged(SurfaceHolder holder,


int


format,


int


width,


int


height)


//重写onSurfaceChanged方法

075



{


076



super


.onSurfaceChanged(holder, format, width, height);


//调用父类对应方法

077


078



Constant.SCREEN_HEIGHT=height;


//初始化宽和高

079



Constant.SCREEN_WIDTH=width;

080


081



int


[] ballsSize={Constant.YELLOW_BALL_SIZE,Constant.BLUE_BALL_SIZE,Constant.GREEN_BALL_SIZE};


//所有球尺寸数组

082



Bitmap[] ballsBitmap={yellowBallBitmap,blueBallBitmap,greenBallBitmap};


//所有球位图数组

083



int


[] ballsXspan={Constant.YELLOW_XSPAN,Constant.BLUE_XSPAN,Constant.GREEN_XSPAN};


//所有球的xSpan数组

084



int


[] ballsYspan={Constant.YELLOW_YSPAN,Constant.BLUE_YSPAN,Constant.GREEN_YSPAN};


//所有球的ySpan数组

085



allBalls=


new


AllBalls(ballsSize,ballsBitmap,ballsXspan,ballsYspan);


//创建AllBalls对象

086



}

087

088



@Override

089



public


void


onSurfaceCreated(SurfaceHolder holder)


//重写onSurfaceCreated方法

090



{


091



super


.onSurfaceCreated(holder);


//调用父类对应方法

092



}

093

094



@Override

095



public


void


onSurfaceDestroyed(SurfaceHolder holder)


//重写onSurfaceDestroyed方法

096



{


097



super


.onSurfaceDestroyed(holder);


//调用父类对应方法

098



}

099



void


drawBalls()


//绘制所有球的方法

100



{


101



final


SurfaceHolder holder = getSurfaceHolder();


//获得SurfaceHolder对象

102



Canvas canvas =


null


;


//声明画布引用

103



try

104



{


105



canvas = holder.lockCanvas();


//锁定并获得画布对象

106



if


(canvas !=


null


)


//如果已得到画布对象

107



{


108



canvas.drawColor(Color.argb(


255


,


0


,


0


,


0


));


//擦空界面

109



allBalls.drawSelf(canvas, paint);


//绘制所有的球

110



}

111



}

112



finally

113



{


114



if


(canvas !=


null


) holder.unlockCanvasAndPost(canvas);


//绘制完释放画布

115



}

116



if


(ifDraw)


//如果桌面可见

117



{


118



hd.postDelayed(mDrawCube,Constant.MOVE_TIME);


//一定时间后绘制球

119



}

120



}

121



}

122

}

定义常量的类:


01

package


com.bn.ex12f;

02

/*

03



* 横竖屏公共常量类

04



*/

05

public


class


Constant {


06



public


static


int


SCREEN_WIDTH;


//屏幕宽度

07



public


static


int


SCREEN_HEIGHT;


//屏幕高度

08


09



public


static


final


int


MOVE_TIME=


10


;


//绘制所有球的时间间隔

10



public


static


final


int


YELLOW_XSPAN=


1


;


//黄球x方向步进

11



public


static


final


int


YELLOW_YSPAN=


1


;


//黄球y方向步进

12



public


static


final


int


BLUE_XSPAN=


1


;


//蓝球x方向步进

13



public


static


final


int


BLUE_YSPAN=


1


;


//蓝球y方向步进

14



public


static


final


int


GREEN_XSPAN=


1


;


//绿球x方向步进

15



public


static


final


int


GREEN_YSPAN=


1


;


//绿球y方向步进

16


17



public


static


final


int


YELLOW_BALL_SIZE=


42


;


//黄球尺寸

18



public


static


final


int


BLUE_BALL_SIZE=


39


;


//蓝球尺寸

19



public


static


final


int


GREEN_BALL_SIZE=


35


;


//绿球尺寸

20

}

定义单个球控制的类:


001

package


com.bn.ex12f;

002

003

import


android.graphics.Bitmap;

004

import


android.graphics.Canvas;

005

import


android.graphics.Paint;

006

/*

007



* 表示单个球的类

008



*/

009

public


class


SingleBall {


010



public


static


final


int


DIRECTION_YS=


0


;


//右上

011



public


static


final


int


DIRECTION_ZS=


1


;


//左上

012



public


static


final


int


DIRECTION_ZX=


2


;


//左下

013



public


static


final


int


DIRECTION_YX=


3


;


//右下

014



int


x;


//球位置坐标

015



int


y;

016



int


size;


//球的尺寸

017



int


xSpan=


2


;


//球x方向的步进

018



int


ySpan=


2


;


//球y方向的步进

019



int


direction;


//球的运动方向

020



Bitmap bitmap;


//球的位图

021



public


SingleBall(


int


x,


int


y,


int


size,


int


direction,Bitmap bitmap,


int


xSpan,


int


ySpan)


//构造器

022



{


023



this


.x=x;


//初始化坐标位置

024



this


.y=y;

025



this


.size=size;


//初始化球的尺寸

026



this


.bitmap=bitmap;


//初始化球的位图

027



this


.direction=direction;


//球的运动方向

028



this


.xSpan=xSpan;


//初始化x方向的步进

029



this


.ySpan=ySpan;


//初始化y方向的步进

030



}

031



void


drawSelf(Canvas canvas, Paint paint)


//绘制单个球的方法

032



{


033



canvas.drawBitmap(bitmap, x,y, paint);

034



}

035



void


go()


//单个球运动的方法

036



{


037



int


tempX,tempY;


//球的目标位置

038



switch


(direction)

039



{


040



case


DIRECTION_YS:


//如果在向右上方运动

041



tempX=x+xSpan;


//计算目标位置坐标

042



tempY=y-ySpan;

043



if


(isCollideWithRight(tempX,tempY))


//到达屏幕右侧

044



{


045



direction=DIRECTION_ZS;


//改变运动方向为左上

046



}

047



else


if


(isCollideWithUp(tempX,tempY))


//到达屏幕上侧

048



{


049



direction=DIRECTION_YX;


//改变运动方向为右下

050



}

051



else


//如果没有碰撞

052



{


053



x=tempX;


//更新坐标位置

054



y=tempY;

055



}

056



break


;

057



case


DIRECTION_ZS:


//如果在向左上方运动

058



tempX=x-xSpan;


//计算目标位置坐标

059



tempY=y-ySpan;

060



if


(isCollideWithLeft(tempX,tempY))


//到达屏幕左侧

061



{


062



direction=DIRECTION_YS;


//改变运动方向为右上

063



}

064



else


if


(isCollideWithUp(tempX,tempY))


//到达屏幕上侧

065



{


066



direction=DIRECTION_ZX;


//改变运动方向为左下

067



}

068



else


//如果没有碰撞

069



{


070



x=tempX;


//更新坐标位置

071



y=tempY;

072



}

073



break


;

074



case


DIRECTION_ZX:


//如果在向左下方运动

075



tempX=x-xSpan;


//计算目标位置坐标

076



tempY=y+ySpan;

077



if


(isCollideWithLeft(tempX,tempY))


//到达屏幕左侧

078



{


079



direction=DIRECTION_YX;


//改变运动方向为右下

080



}

081



else


if


(isCollideWithDown(tempX,tempY))


//到达屏幕下侧

082



{


083



direction=DIRECTION_ZS;


//改变运动方向为左上

084



}

085



else


//如果没有碰撞

086



{


087



x=tempX;


//更新坐标位置

088



y=tempY;

089



}

090



break


;

091



case


DIRECTION_YX:


//如果在向右下方运动

092



tempX=x+xSpan;


//计算目标位置坐标

093



tempY=y+ySpan;

094



if


(isCollideWithRight(tempX,tempY))


//到达屏幕右侧

095



{


096



direction=DIRECTION_ZX;


//改变运动方向为左下

097



}

098



else


if


(isCollideWithDown(tempX,tempY))


//到达屏幕下侧

099



{


100



direction=DIRECTION_YS;


//改变运动方向为右上

101



}

102



else


//如果没有碰撞

103



{


104



x=tempX;


//更新坐标位置

105



y=tempY;

106



}

107



break


;

108



}

109



}

110



boolean


isCollideWithRight(


int


tempX,


int


tempY)


//判断是否与屏右侧碰撞的方法

111



{


112



return


!(tempX>


0


&&tempX<Constant.SCREEN_WIDTH -


this


.size *


1.5


);

113



}

114



boolean


isCollideWithUp(


int


tempX,


int


tempY)


//判断是否与屏上侧碰撞的方法

115



{


116



return


!(tempY>


0


);

117



}

118



boolean


isCollideWithLeft(


int


tempX,


int


tempY)


//判断是否与屏左侧碰撞的方法

119



{


120



return


!(tempX>


0


);

121



}

122



boolean


isCollideWithDown(


int


tempX,


int


tempY)


//判断是否与屏下侧碰撞的方法

123



{


124



return


!(tempY>


0


&&tempY<Constant.SCREEN_HEIGHT -


this


.size *


1.5


);

125



}

126

}

管理所有球运动的类:


01

package


com.bn.ex12f;

02

/*

03



* 控制所有球的类

04



*/

05

import


java.util.ArrayList;

06

import


android.graphics.Bitmap;

07

import


android.graphics.Canvas;

08

import


android.graphics.Paint;

09

10

public


class


AllBalls {

11



ArrayList<SingleBall> alSingleBall=


new


ArrayList<SingleBall>();


//单个球列表

12



Bitmap[] ballsBitmap;


//位图数组

13



int


[] ballsSize;


//球尺寸数组

14



int


[] ballsXSpan;


//球x方向步进数组

15



int


[] ballsYSpan;


//球y方向步进数组

16



public


AllBalls(


int


[] ballsSize,Bitmap[] ballsBitmap,


int


[] ballsXSpan,


int


[] ballsYSpan)


//构造器

17



{


18



this


.ballsSize=ballsSize;


//成员变量赋值

19



this


.ballsBitmap=ballsBitmap;


//成员变量赋值

20



this


.ballsXSpan=ballsXSpan;


//成员变量赋值

21



this


.ballsYSpan=ballsYSpan;


//成员变量赋值

22



for


(


int


i=


0


;i<ballsSize.length;i++)


//循环球尺寸数组

23



{


24



int


x=(


int


) (Math.random()*(Constant.SCREEN_WIDTH-ballsSize[i]));


//随机生成单个球的初始位置

25



int


y=(


int


) (Math.random()*(Constant.SCREEN_HEIGHT-ballsSize[i]));

26



int


direction=(


int


) Math.random()*


4


;


//随机生成单个球的运动方向

27



alSingleBall.add


//创建单个球对象,并加入列表

28



(

29



new


SingleBall(x,y,ballsSize[i],direction,ballsBitmap[i],ballsXSpan[i],ballsYSpan[i])

30

31



);

32



}

33



}

34



public


void


drawSelf(Canvas canvas, Paint paint)


//绘制所有球的方法

35



{


36



for


(SingleBall sb:alSingleBall)


//循环单个球列表

37



{


38



sb.drawSelf(canvas, paint);


//绘制单个球

39



}

40



}

41



public


void


go()


//使所有球运动的方法

42



{


43



for


(SingleBall sb:alSingleBall)


//循环单个球列表

44



{


45



sb.go();


//使单个球运动

46



}

47



}

48

}

最后是启动球运动的线程类:


01

package


com.bn.ex12f;

02

/*

03



* 控制所有球运动的线程

04



*/

05

public


class


BallGoThread


extends


Thread {


06



AllBalls allBalls;


//声明AllBalls的引用

07



public


BallGoThread(AllBalls allBalls)


//构造器

08



{


09



this


.allBalls=allBalls;


//成员变量赋值

10



}

11



boolean


ballGoFlag=


true


;


//循环标志位

12



@Override

13



public


void


run()


//重写run方法

14



{


15



while


(ballGoFlag)


//while循环

16



{


17



allBalls.go();


//调用使所有球运动的方法

18



try

19



{


20



Thread.sleep(Constant.MOVE_TIME);


//一段时间后再运动

21



}

22



catch


(Exception e)

23



{


24



e.printStackTrace();


//打印异常

25



}

26



}

27



}

28

}

转自:http://www.cnblogs.com/carmanloneliness/archive/2012/03/10/2388500.html

转载于:https://www.cnblogs.com/hmyprograming/archive/2012/03/23/2414159.html