Android动态壁纸的制作教程
动态壁纸是在Android 2.1新增的一个功能。动态壁纸可以添加到Android的桌面,具有交互式的动画背景效果。在本教程中,我们将教会你如何去制作一个交互式的动态壁纸。
动态壁纸是一个Android应用程序,包括一个服务(WallpaperService)。该服务必须包括一个引擎(WallpaperService.Engine)。该引擎是连接用户、桌面、系统之间的桥梁。它也可以绘制桌面壁纸。
首先,必须由内在的Engine类创建一个WallpaperService类。该服务必须在AndroidManifest.xml中声明为"android.service.wallpaper.WallpaperService",这样它才会作为动态壁纸被手机识别。而且还要在服务配置中附加"android.permission.BIND_WALLPAPER"的权限许可:
<service
android:name="LiveWallpaperService"
android:enabled="true"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:permission="android.permission.BIND_WALLPAPER">
<intent-filter android:priority="1" >
<action android:name="android.service.wallpaper.WallpaperService" />
</intent-filter>
<meta-data
android:name="android.service.wallpaper"
android:resource="@xml/wallpaper" />
</service>
创建一个XML文件,放置在应用程序目录下的/res/xml/中。它用来描述你的动态壁纸。
<?xml version="1.0" encoding="UTF-8"?>
<wallpaper
xmlns:android="http://schemas.android.com/apk/res/android"
android:thumbnail="@drawable/thumbnail"
android:description="@string/description"
android:settingsActivity="PreferenceActivity"/>
再创建一个xml的属性文件 attrs.xml ,代码如下:
<declare-styleable name="Wallpaper">
<!-- Component name of an activity that allows the user to modify
the current settings for this wallpaper. -->
<attr name="settingsActivity" />
<!-- Reference to a the wallpaper's thumbnail bitmap. -->
<attr name="thumbnail" format="reference" />
<!-- Name of the author of this component, e.g. Google. -->
<attr name="author" format="reference" />
<!-- Short description of the component's purpose or behavior. -->
<attr name="description" />
</declare-styleable>
动态壁纸的服务代码如下
packagenet.androgames.blog.sample.livewallpaper;importandroid.content.SharedPreferences;
importandroid.service.wallpaper.WallpaperService;
importandroid.view.MotionEvent;
importandroid.view.SurfaceHolder;
/**
*AndroidLiveWallpaperArchetype
* @author antoinevianey
*underGPLv3: http://www.gnu.org/licenses/gpl-3.0.html
*/
public classLiveWallpaperService extendsWallpaperService{
@Override
publicEngineonCreateEngine(){
return newSampleEngine();
}
@Override
public voidonCreate(){
super.onCreate();
}
@Override
public voidonDestroy(){
super.onDestroy();
}
public classSampleEngine extendsEngine{
privateLiveWallpaperPaintingpainting;
SampleEngine(){
SurfaceHolderholder=getSurfaceHolder();
painting= newLiveWallpaperPainting(holder,
getApplicationContext());
}
@Override
public voidonCreate(SurfaceHoldersurfaceHolder){
super.onCreate(surfaceHolder);
// registerlistenersandcallbackshere
setTouchEventsEnabled( true);
}
@Override
public voidonDestroy(){
super.onDestroy();
// removelistenersandcallbackshere
painting.stopPainting();
}
@Override
public voidonVisibilityChanged( booleanvisible){
if(visible){
// registerlistenersandcallbackshere
painting.resumePainting();
} else{
// removelistenersandcallbackshere
painting.pausePainting();
}
}
@Override
public voidonSurfaceChanged(SurfaceHolderholder, intformat,
intwidth, intheight){
super.onSurfaceChanged(holder,format,width,height);
painting.setSurfaceSize(width,height);
}
@Override
public voidonSurfaceCreated(SurfaceHolderholder){
super.onSurfaceCreated(holder);
// startpainting
painting.start();
}
@Override
public voidonSurfaceDestroyed(SurfaceHolderholder){
super.onSurfaceDestroyed(holder);
booleanretry= true;
painting.stopPainting();
while(retry){
try{
painting.join();
retry= false;
} catch(InterruptedExceptione){}
}
}
@Override
public voidonOffsetsChanged( floatxOffset, floatyOffset,
floatxStep, floatyStep, intxPixels, intyPixels){
}
@Override
public voidonTouchEvent(MotionEventevent){
super.onTouchEvent(event);
painting.doTouchEvent(event);
}
}
}
当壁纸的显示、状态或大小变化是,会调用Engine的onCreate, onDestroy, onVisibilityChanged, onSurfaceChanged, onSurfaceCreated 和 onSurfaceDestroyed方法。有了这些方法,动态壁纸才能展现出动画效果。而通过设置setTouchEventsEnabled(true),并且调用onTouchEvent(MotionEvent event)方法,来激活触摸事件。
我们在绘画墙纸的时候,也会使用一个单独的绘画线程
packagenet.androgames.blog.sample.livewallpaper;importandroid.content.Context;
importandroid.graphics.Canvas;
importandroid.view.MotionEvent;
importandroid.view.SurfaceHolder;
/**
*AndroidLiveWallpaperpaintingthreadArchetype
* @author antoinevianey
*GPLv3: http://www.gnu.org/licenses/gpl-3.0.html
*/
public classLiveWallpaperPainting extendsThread{
/** ReferencetotheViewandthecontext */
privateSurfaceHoldersurfaceHolder;
privateContextcontext;
/** State */
private booleanwait;
private booleanrun;
/** Dimensions */
private intwidth;
private intheight;
/** Timetracking */
private longpreviousTime;
private longcurrentTime;
publicLiveWallpaperPainting(SurfaceHoldersurfaceHolder,
Contextcontext){
// keepareferenceofthecontextandthesurface
// thecontextisneededifyouwanttoinflate
// someresourcesfromyourlivewallpaper.apk
this.surfaceHolder=surfaceHolder;
this.context=context;
// don'tanimateuntilsurfaceiscreatedanddisplayed
this.wait= true;
}
/**
*Pausesthelivewallpaperanimation
*/
public voidpausePainting(){
this.wait= true;
synchronized( this){
this.notify();
}
}
/**
*Resumethelivewallpaperanimation
*/
public voidresumePainting(){
this.wait= false;
synchronized( this){
this.notify();
}
}
/**
*Stopthelivewallpaperanimation
*/
public voidstopPainting(){
this.run= false;
synchronized( this){
this.notify();
}
}
@Override
public voidrun(){
this.run= true;
Canvasc= null;
while(run){
try{
c= this.surfaceHolder.lockCanvas( null);
synchronized( this.surfaceHolder){
currentTime=System.currentTimeMillis();
updatePhysics();
doDraw(c);
previousTime=currentTime;
}
} finally{
if(c!= null){
this.surfaceHolder.unlockCanvasAndPost(c);
}
}
// pauseifnoneedtoanimate
synchronized( this){
if(wait){
try{
wait();
} catch(Exceptione){}
}
}
}
}
/**
*Invokewhenthesurfacedimensionchange
*/
public voidsetSurfaceSize( intwidth, intheight){
this.width=width;
this.height=height;
synchronized( this){
this.notify();
}
}
/**
*Invokewhilethescreenistouched
*/
public voiddoTouchEvent(MotionEventevent){
// handletheeventhere
// ifthereissomethingtoanimate
// thenwakeup
this.wait= false;
synchronized( this){
notify();
}
}
/**
*Dotheactualdrawingstuff
*/
private voiddoDraw(Canvascanvas){}
/**
*Updatetheanimation,spritesorwhatever.
*Ifthereisnothingtoanimatesetthewait
*attributeofthethreadtotrue
*/
private voidupdatePhysics(){
// ifnothingwasupdated:
// this.wait=true;
}
}
如果桌面壁纸是可见状态下,系统服务通知有新的东西,这个类会优先把它绘制在画布上。如果没有动画了,updatePhysics会通知线程去等待。通常SurfaceView在有两个画布交替绘制的时候,会在画布上绘制上一次......
如果要让你的动态墙纸有配置功能,只要创建一个PreferenceActivity,并将它在wallpaper.xml文件中声明。同时让SharedPreference对象可以找到你的配置选项。
教程就写到这里,如果还有什么不懂,你可以通过Eclipse来浏览完整的源代码:SampleLiveWallpaper
更多相关文章
- Android调Ajax和动态添加JS中的token(Android 和JS完全交互)
- Android 程序的动态调试
- android静态图片和动态壁纸
- Android动态部署五:如何从插件apk中启动Service
- Android UI详解之动态布局
- Android N 固定壁纸大小不拉伸
- android 设置壁纸几种方法
- 手机壁纸设置相关