转自:http://www.ophonesdn.com/article/show/278
OPhone动态壁纸探究
OPhone平台开发,2010-08-06 14:50:47
标签:
动态壁纸
Live
Wallpapers
时间壁纸
TimeWall
随着三星Oscar的上市,流畅的操作,华丽的界面,OPhone 2.0的不俗表现不禁让人眼前一亮。作为OPhone 2.0一个新特性,动态壁纸(Live Wallpapers)为用户带来了更炫体验。本文主要通过一个完整的时间壁纸(TimeWall)为大家介绍如何开发 Live Wallpapers。还没开发环境?赶紧去下载OPhone SDK 2.0吧!
1、 Live Wallpapers是什么?
在
oscar上有一个动态壁纸叫“天空草地”,用过一段时间,可以发现,随着时间的变化,壁纸的天空就会由蓝蓝青天变成繁星满天。看看效果:
oscar上有一个动态壁纸叫“天空草地”,用过一段时间,可以发现,随着时间的变化,壁纸的天空就会由蓝蓝青天变成繁星满天。看看效果:
为什么壁纸还有这么神奇的变化,这中间到底是什么在起作用?其实,一个
Live Wallpaper就是一个apk!也就是说,动态壁纸的实质是一个apk在后台不断地重绘壁纸,所以我们可以让小草长高,小鸟飞翔。
Live Wallpaper就是一个apk!也就是说,动态壁纸的实质是一个apk在后台不断地重绘壁纸,所以我们可以让小草长高,小鸟飞翔。
来看一下我们
TimeWall的AndoridManifest.xml:
TimeWall的AndoridManifest.xml:
-
<?xml version=
“1.0”
encoding=
“utf-8”
?> -
<manifest xmlns:android=
“http://schemas.android.com/apk/res/android”
-
package
=
“com.oms.LiveWall”
android:versionCode=
“1”
-
android:versionName=
“1.0”
> -
<application android:icon=
“@drawable/icon”
android:label=
“@string/app_name”
> -
<service android:label=
“@string/app_name”
android:name=
“.TimeWall”
-
android:permission=
“android.permission.BIND_WALLPAPER”
> - <intent-filter>
-
<action android:name=
“android.service.wallpaper.WallpaperService”
/> - </intent-filter>
-
<meta-data android:name=
“android.service.wallpaper”
-
android:resource=
“@xml/alive_wall”
/> - </service>
- </application>
-
<uses-sdk android:minSdkVersion=
“7”
/> - </manifest>
原来如此简单,动态壁纸仅仅有一个
service就够了。其中
service就够了。其中
android:permission
=”android.permission.BIND_WALLPAPER”
=”android.permission.BIND_WALLPAPER”
是让该
service有能设置为壁纸的权限,没有的话该壁纸只能被预览。
service有能设置为壁纸的权限,没有的话该壁纸只能被预览。
<uses-sdk
android:minSdkVersion=
“7”
/>
android:minSdkVersion=
“7”
/>
告诉我们,如果你想开发一个
live wallpaper,必须是OPhone 2.0或者更高的版本。当然这也需要手机硬件的支持。
live wallpaper,必须是OPhone 2.0或者更高的版本。当然这也需要手机硬件的支持。
2、怎样实现WallpaperService?
WallpaperService与其他的
service唯一的不同就是,你必须要增加一个方法onCreateEngine(),它会返回一个WallpaperService.Engine,这个engine才是负责绘制壁纸以及响应与用户交互事件的核心部件。这个service代码结构如下:
service唯一的不同就是,你必须要增加一个方法onCreateEngine(),它会返回一个WallpaperService.Engine,这个engine才是负责绘制壁纸以及响应与用户交互事件的核心部件。这个service代码结构如下:
-
public
class
TimeWall
extends
WallpaperService { -
public
Engine onCreateEngine() { -
return
new
TimeEngine(); - }
-
public
class
TimeEngine
extends
Engine { -
// …more code
- }
- }
类TimeEngine才是处理壁纸的核心类,我们会在类TimeEngine中加上自己的逻辑以完成壁纸的绘制、变化以及销毁。Engine的生命周期与大多数OPhone应用程序组件,比如activity类似,都是从onCreate()开始,在销毁时调用onDestory()方法。不同的是WallpaperService会提供一个surface用来绘制壁纸,所以在生命周期中多一个onSurfaceCreated与onSurfaceDestroyed的过程。下面是一个最简生命周期:
也就是说只要我们实现上面四个方法,一个基本的LiveWallpaper就可以完成了。让我们逐个看一下这几个方法的实现。
-
@Override
-
public
void
onCreate(SurfaceHolder surfaceHolder) { -
super
.onCreate(surfaceHolder); -
setTouchEventsEnabled(
true
); - }
-
@Override
-
public
void
onDestroy() { -
super
.onDestroy(); - mHandler.removeMessages(DRAW);
- }
-
@Override
-
public
void
onSurfaceCreated(SurfaceHolder holder) { -
super
.onSurfaceCreated(holder); - mHandler.sendEmptyMessage(DRAW);
- }
-
@Override
-
public
void
onSurfaceDestroyed(SurfaceHolder holder) { -
super
.onSurfaceDestroyed(holder); - mHandler.removeMessages(DRAW);
- }
在
onCreate方法里,我们
onCreate方法里,我们
setTouchEventsEnabled(
true
);
true
);
作用是使壁纸能响应
touch event,默认是false。TimeWall会在用户点击屏幕的时候画一个十字架,所以我们需要设置其为true。
touch event,默认是false。TimeWall会在用户点击屏幕的时候画一个十字架,所以我们需要设置其为true。
可以看到我们在这四个方法里面做的事情非常简单,就是在
create时候发一个message,执行画面的绘制,在destory时remove这个消息。看一下mHandler的代码:
create时候发一个message,执行画面的绘制,在destory时remove这个消息。看一下mHandler的代码:
-
private
Handler mHandler =
new
Handler() { -
public
void
handleMessage(Message msg) { -
switch
(msg.what) { -
case
DRAW: - drawWall();
-
break
; - }
- }
- };
方法
drawWall():
drawWall():
-
private
void
drawWall() { - SurfaceHolder holder = getSurfaceHolder();
- Canvas canvas = holder.lockCanvas();
- drawTime(canvas);
- drawCross(canvas);
- holder.unlockCanvasAndPost(canvas);
- mHandler.removeMessages(DRAW);
-
mHandler.sendEmptyMessageDelayed(DRAW,
50
); - }
从上面可以看出,动态壁纸实际上就是不断刷新的静态壁纸,越华丽越流畅,
CPU就消耗越大,对于现在的本来电量就不怎么地的智能机来说,耗电也是很可观的。但是偶尔向朋友们炫一下还是绝对可行的。drawTime()与drawCross()的内容可以由家自己实现,在TimeWall里,它们比较简单。drawTime()是计算下一处Time String应该移动到的坐标,以及画出这个String。drawCross()的作用是在用户触发onTouchEvent时画一个十字架。因为TimeWall比较简单,如果大家自己实现的画图比较复杂,可以另外开启一个线程来刷新UI,否则有可能主线程被阻塞掉。(代码见附件)
CPU就消耗越大,对于现在的本来电量就不怎么地的智能机来说,耗电也是很可观的。但是偶尔向朋友们炫一下还是绝对可行的。drawTime()与drawCross()的内容可以由家自己实现,在TimeWall里,它们比较简单。drawTime()是计算下一处Time String应该移动到的坐标,以及画出这个String。drawCross()的作用是在用户触发onTouchEvent时画一个十字架。因为TimeWall比较简单,如果大家自己实现的画图比较复杂,可以另外开启一个线程来刷新UI,否则有可能主线程被阻塞掉。(代码见附件)
看看TimeWall的效果:
附件代码:
-
package
com.OPhonesdn.timewall; -
import
java.text.SimpleDateFormat; -
import
java.util.Date; -
import
android.graphics.Canvas; -
import
android.graphics.Color; -
import
android.graphics.Paint; -
import
android.os.Handler; -
import
android.os.Message; -
import
android.service.wallpaper.WallpaperService; -
import
android.view.MotionEvent; -
import
android.view.SurfaceHolder; -
public
class
TimeWall
extends
WallpaperService { -
public
Engine onCreateEngine() { -
return
new
TimeEngine(); - }
-
public
class
TimeEngine
extends
Engine { -
private
final
float
STEP_X = 2f; -
private
final
float
STEP_Y = 7f; -
private
final
float
SCOPE_LEFT = 10f; -
private
final
float
SCOPE_RIGHT = 110f; -
private
final
float
SCOPE_TOP = 250f; -
private
final
float
SCOPE_BOTTOM = 600f; -
private
final
float
RADIUS = 20f; -
private
final
int
DIRECTION_1 =
1
;
// move to right top side
-
private
final
int
DIRECTION_2 =
2
;
// move to right bottom side
-
private
final
int
DIRECTION_3 =
3
;
// move to left bottom side
-
private
final
int
DIRECTION_4 =
4
;
// move to left top side
-
private
final
int
DRAW =
1
; -
private
float
mTouchX = -1f; -
private
float
mTouchY = -1f; -
private
float
mLocationX = 0f; -
private
float
mLocationY = 400f; -
private
int
mDirection =
1
; -
private
Paint mPaint =
new
Paint(); -
private
Handler mHandler =
new
Handler() { -
public
void
handleMessage(Message msg) { -
switch
(msg.what) { -
case
DRAW: - drawWall();
-
break
; - }
- }
- };
-
public
TimeEngine() { - mPaint.setColor(Color.RED);
-
mPaint.setAntiAlias(
true
); -
mPaint.setStrokeWidth(
4
); - mPaint.setStrokeCap(Paint.Cap.BUTT);
- mPaint.setStyle(Paint.Style.STROKE);
-
mPaint.setTextSize(
40
); - }
-
@Override
-
public
void
onCreate(SurfaceHolder surfaceHolder) { -
super
.onCreate(surfaceHolder); -
setTouchEventsEnabled(
true
); - }
-
@Override
-
public
void
onDestroy() { -
super
.onDestroy(); - mHandler.removeMessages(DRAW);
- }
-
@Override
-
public
void
onSurfaceCreated(SurfaceHolder holder) { -
super
.onSurfaceCreated(holder); - mHandler.sendEmptyMessage(DRAW);
- }
-
@Override
-
public
void
onSurfaceDestroyed(SurfaceHolder holder) { -
super
.onSurfaceDestroyed(holder); - mHandler.removeMessages(DRAW);
- }
-
@Override
-
public
void
onTouchEvent(MotionEvent event) { -
if
(event.getAction() == MotionEvent.ACTION_MOVE - || event.getAction() == MotionEvent.ACTION_DOWN) {
- mTouchX = event.getX();
- mTouchY = event.getY();
-
}
else
{ -
mTouchX = –
1
; -
mTouchY = –
1
; - }
-
super
.onTouchEvent(event); - }
-
private
void
drawWall() { - SurfaceHolder holder = getSurfaceHolder();
- Canvas canvas = holder.lockCanvas();
- drawTime(canvas);
- drawCross(canvas);
- holder.unlockCanvasAndPost(canvas);
- mHandler.removeMessages(DRAW);
-
mHandler.sendEmptyMessageDelayed(DRAW,
50
); - }
-
private
void
drawTime(Canvas c) { -
Date date =
new
Date(System.currentTimeMillis()); -
SimpleDateFormat sdf =
new
SimpleDateFormat(
“yyyy-MM-dd HH:mm:ss”
); - String strDate = sdf.format(date);
- c.save();
-
c.drawColor(
0xff000000
); - c.drawText(strDate, mLocationX, mLocationY, mPaint);
-
switch
(mDirection) { -
case
DIRECTION_1: - mLocationX = mLocationX + STEP_X;
- mLocationY = mLocationY – STEP_Y;
-
if
(mLocationY <= SCOPE_TOP) { - mDirection = DIRECTION_2;
- }
-
break
; -
case
DIRECTION_2: - mLocationX = mLocationX + STEP_X;
- mLocationY = mLocationY + STEP_Y;
-
if
(mLocationX >= SCOPE_RIGHT) { - mDirection = DIRECTION_3;
- }
-
break
; -
case
DIRECTION_3: - mLocationX = mLocationX – STEP_X;
- mLocationY = mLocationY + STEP_Y;
-
if
(mLocationY >= SCOPE_BOTTOM) { - mDirection = DIRECTION_4;
- }
-
break
; -
case
DIRECTION_4: - mLocationX = mLocationX – STEP_X;
- mLocationY = mLocationY – STEP_Y;
-
if
(mLocationX <= SCOPE_LEFT) { - mDirection = DIRECTION_1;
- }
-
break
; - }
- c.restore();
- }
-
private
void
drawCross(Canvas c) { -
if
(mTouchX >=
0
&& mTouchY >=
0
) { - c.drawLine(mTouchX – RADIUS, mTouchY, mTouchX + RADIUS,
- mTouchY, mPaint);
- c.drawLine(mTouchX, mTouchY – RADIUS, mTouchX,
- mTouchY + RADIUS, mPaint);
- }
- }
- }
- }
