最近做动态壁纸的项目,原来觉得动态壁纸是个很小的项目,但是看到Android Market上有个专门的动态壁纸分类(现在升级为Google Play了), 而且自己做的这个项目可连接上服务器,供用户购买下载图片,终于有了自信,认识到这个不算是个小项目了。接下来我主要谈谈动态壁纸的原理,然后会解释一个 “小球的例子”,供大家能深入的理解该原理。
一:原理
动态壁纸为:在手机上点击 Menu→Wallpapers→Live wallpapers→然后打开自己的程序。建个最简单的动态壁纸的步骤如下:
1.在rex/xml中新建一个.xml.其中注册一个wallpaper.假设这个名字为ab.xml(下文要用到,可随意设置,没要求)
最简单的就是写 这一句,这样的话打开动态壁纸就会出现只出现一个按钮(左图),一般我们不这样做,要像右图这样子。
若动态壁纸"设置..."(Setting...)你想连接Activity,也在这里指定,比如:
android:settingsActivity="com.birbeck.wallpaperslideshow.SettingsActivity" (这个一般是继承了PreferenceActivity类的Activity。就是首选项模式的类),要设置了这个属性,就会如有图所示了。
如上截图是手机上的动态壁纸列表,你也可以通过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 )
这个是继承了WallpaerService的类的代码。
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; |
012 | public class Sample12_6_WallPaper extends WallpaperService |
015 | Handler hd = new Handler(); |
016 | Bitmap yellowBallBitmap; |
017 | Bitmap blueBallBitmap; |
018 | Bitmap greenBallBitmap; |
020 | public Engine onCreateEngine() |
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); |
031 | class BallEngine extends Engine |
033 | Sample12_6_WallPaper father; |
034 | private final Paint paint = new Paint(); |
036 | BallGoThread bgThread; |
038 | private final Runnable mDrawCube = new Runnable() { |
044 | public void onCreate(SurfaceHolder surfaceHolder) |
046 | super .onCreate(surfaceHolder); |
047 | paint.setAntiAlias( true ); |
052 | public void onDestroy() |
058 | public void onVisibilityChanged( boolean visible) |
063 | bgThread= new BallGoThread(allBalls); |
065 | hd.postDelayed(mDrawCube, Constant.MOVE_TIME); |
069 | bgThread.ballGoFlag= false ; |
074 | public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) |
076 | super .onSurfaceChanged(holder, format, width, height); |
078 | Constant.SCREEN_HEIGHT=height; |
079 | Constant.SCREEN_WIDTH=width; |
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}; |
084 | int [] ballsYspan={Constant.YELLOW_YSPAN,Constant.BLUE_YSPAN,Constant.GREEN_YSPAN}; |
085 | allBalls= new AllBalls(ballsSize,ballsBitmap,ballsXspan,ballsYspan); |
089 | public void onSurfaceCreated(SurfaceHolder holder) |
091 | super .onSurfaceCreated(holder); |
095 | public void onSurfaceDestroyed(SurfaceHolder holder) |
097 | super .onSurfaceDestroyed(holder); |
101 | final SurfaceHolder holder = getSurfaceHolder(); |
102 | Canvas canvas = null ; |
105 | canvas = holder.lockCanvas(); |
108 | canvas.drawColor(Color.argb( 255 , 0 , 0 , 0 )); |
109 | allBalls.drawSelf(canvas, paint); |
114 | if (canvas != null ) holder.unlockCanvasAndPost(canvas); |
118 | hd.postDelayed(mDrawCube,Constant.MOVE_TIME); |
定义常量的类:
05 | public class Constant { |
06 | public static int SCREEN_WIDTH; |
07 | public static int SCREEN_HEIGHT; |
09 | public static final int MOVE_TIME= 10 ; |
10 | public static final int YELLOW_XSPAN= 1 ; |
11 | public static final int YELLOW_YSPAN= 1 ; |
12 | public static final int BLUE_XSPAN= 1 ; |
13 | public static final int BLUE_YSPAN= 1 ; |
14 | public static final int GREEN_XSPAN= 1 ; |
15 | public static final int GREEN_YSPAN= 1 ; |
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 ; |
定义单个球控制的类:
003 | import android.graphics.Bitmap; |
004 | import android.graphics.Canvas; |
005 | import android.graphics.Paint; |
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 ; |
021 | public SingleBall( int x, int y, int size, int direction,Bitmap bitmap, int xSpan, int ySpan) |
027 | this .direction=direction; |
031 | void drawSelf(Canvas canvas, Paint paint) |
033 | canvas.drawBitmap(bitmap, x,y, paint); |
043 | if (isCollideWithRight(tempX,tempY)) |
045 | direction=DIRECTION_ZS; |
047 | else if (isCollideWithUp(tempX,tempY)) |
049 | direction=DIRECTION_YX; |
060 | if (isCollideWithLeft(tempX,tempY)) |
062 | direction=DIRECTION_YS; |
064 | else if (isCollideWithUp(tempX,tempY)) |
066 | direction=DIRECTION_ZX; |
077 | if (isCollideWithLeft(tempX,tempY)) |
079 | direction=DIRECTION_YX; |
081 | else if (isCollideWithDown(tempX,tempY)) |
083 | direction=DIRECTION_ZS; |
094 | if (isCollideWithRight(tempX,tempY)) |
096 | direction=DIRECTION_ZX; |
098 | else if (isCollideWithDown(tempX,tempY)) |
100 | direction=DIRECTION_YS; |
110 | boolean isCollideWithRight( int tempX, int tempY) |
112 | return !(tempX> 0 &&tempX<Constant.SCREEN_WIDTH - this .size * 1.5 ); |
114 | boolean isCollideWithUp( int tempX, int tempY) |
118 | boolean isCollideWithLeft( int tempX, int tempY) |
122 | boolean isCollideWithDown( int tempX, int tempY) |
124 | return !(tempY> 0 &&tempY<Constant.SCREEN_HEIGHT - this .size * 1.5 ); |
管理所有球运动的类:
05 | import java.util.ArrayList; |
06 | import android.graphics.Bitmap; |
07 | import android.graphics.Canvas; |
08 | import android.graphics.Paint; |
10 | public class AllBalls { |
11 | ArrayList<SingleBall> alSingleBall= new ArrayList<SingleBall>(); |
16 | public AllBalls( int [] ballsSize,Bitmap[] ballsBitmap, int [] ballsXSpan, int [] ballsYSpan) |
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++) |
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 ; |
29 | new SingleBall(x,y,ballsSize[i],direction,ballsBitmap[i],ballsXSpan[i],ballsYSpan[i]) |
34 | public void drawSelf(Canvas canvas, Paint paint) |
36 | for (SingleBall sb:alSingleBall) |
38 | sb.drawSelf(canvas, paint); |
43 | for (SingleBall sb:alSingleBall) |
最后是启动球运动的线程类:
05 | public class BallGoThread extends Thread { |
07 | public BallGoThread(AllBalls allBalls) |
09 | this .allBalls=allBalls; |
11 | boolean ballGoFlag= true ; |
20 | Thread.sleep(Constant.MOVE_TIME); |
转自:http://www.cnblogs.com/carmanloneliness/archive/2012/03/10/2388500.html