动态壁纸是在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>

动态壁纸的服务代码如下:

package net.androgames.blog.sample.livewallpaper; import android.content.SharedPreferences;import android.service.wallpaper.WallpaperService;import android.view.MotionEvent;import android.view.SurfaceHolder; /** * Android Live Wallpaper Archetype * @author antoine vianey * under GPL v3 : http://www.gnu.org/licenses/gpl-3.0.html */public class LiveWallpaperService extends WallpaperService {     @Override    public Engine onCreateEngine() {        return new SampleEngine();    }     @Override    public void onCreate() {        super.onCreate();    }     @Override    public void onDestroy() {        super.onDestroy();    }     public class SampleEngine extends Engine {         private LiveWallpaperPainting painting;         SampleEngine() {            SurfaceHolder holder = getSurfaceHolder();            painting = new LiveWallpaperPainting(holder,                 getApplicationContext());        }         @Override        public void onCreate(SurfaceHolder surfaceHolder) {            super.onCreate(surfaceHolder);            // register listeners and callbacks here            setTouchEventsEnabled(true);        }         @Override        public void onDestroy() {            super.onDestroy();            // remove listeners and callbacks here            painting.stopPainting();        }         @Override        public void onVisibilityChanged(boolean visible) {            if (visible) {                // register listeners and callbacks here                painting.resumePainting();            } else {                // remove listeners and callbacks here                painting.pausePainting();            }        }         @Override        public void onSurfaceChanged(SurfaceHolder holder, int format,                 int width, int height) {            super.onSurfaceChanged(holder, format, width, height);            painting.setSurfaceSize(width, height);        }         @Override        public void onSurfaceCreated(SurfaceHolder holder) {            super.onSurfaceCreated(holder);            // start painting            painting.start();        }         @Override        public void onSurfaceDestroyed(SurfaceHolder holder) {            super.onSurfaceDestroyed(holder);            boolean retry = true;            painting.stopPainting();            while (retry) {                try {                    painting.join();                    retry = false;                } catch (InterruptedException e) {}            }        }         @Override        public void onOffsetsChanged(float xOffset, float yOffset,                 float xStep, float yStep, int xPixels, int yPixels) {        }         @Override        public void onTouchEvent(MotionEvent event) {            super.onTouchEvent(event);            painting.doTouchEvent(event);        }     } }

当壁纸的显示、状态或大小变化是,会调用Engine的onCreate, onDestroy, onVisibilityChanged, onSurfaceChanged, onSurfaceCreatedonSurfaceDestroyed方法。有了这些方法,动态壁纸才能展现出动画效果。而通过设置setTouchEventsEnabled(true),并且调用onTouchEvent(MotionEvent event)方法,来激活触摸事件。

我们在绘画墙纸的时候,也会使用一个单独的绘画线程:

package net.androgames.blog.sample.livewallpaper; import android.content.Context;import android.graphics.Canvas;import android.view.MotionEvent;import android.view.SurfaceHolder; /** * Android Live Wallpaper painting thread Archetype * @author antoine vianey * GPL v3 : http://www.gnu.org/licenses/gpl-3.0.html */public class LiveWallpaperPainting extends Thread {     /** Reference to the View and the context */    private SurfaceHolder surfaceHolder;    private Context context;     /** State */    private boolean wait;    private boolean run;     /** Dimensions */    private int width;    private int height;     /** Time tracking */    private long previousTime;    private long currentTime;     public LiveWallpaperPainting(SurfaceHolder surfaceHolder,             Context context) {        // keep a reference of the context and the surface        // the context is needed if you want to inflate        // some resources from your livewallpaper .apk        this.surfaceHolder = surfaceHolder;        this.context = context;        // don't animate until surface is created and displayed        this.wait = true;    }     /**     * Pauses the live wallpaper animation     */    public void pausePainting() {        this.wait = true;        synchronized(this) {            this.notify();        }    }     /**     * Resume the live wallpaper animation     */    public void resumePainting() {        this.wait = false;        synchronized(this) {            this.notify();        }    }     /**     * Stop the live wallpaper animation     */    public void stopPainting() {        this.run = false;        synchronized(this) {            this.notify();        }    }     @Override    public void run() {        this.run = true;        Canvas c = 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);                }            }            // pause if no need to animate            synchronized (this) {                if (wait) {                    try {                        wait();                    } catch (Exception e) {}                }            }        }    }     /**     * Invoke when the surface dimension change     */    public void setSurfaceSize(int width, int height) {        this.width = width;        this.height = height;        synchronized(this) {            this.notify();        }    }     /**     * Invoke while the screen is touched     */    public void doTouchEvent(MotionEvent event) {        // handle the event here        // if there is something to animate        // then wake up        this.wait = false;        synchronized(this) {            notify();        }    }     /**     * Do the actual drawing stuff     */    private void doDraw(Canvas canvas) {}     /**     * Update the animation, sprites or whatever.     * If there is nothing to animate set the wait     * attribute of the thread to true     */    private void updatePhysics() {        // if nothing was updated :        // this.wait = true;    } }

如果桌面壁纸是可见状态下,系统服务通知有新的东西,这个类会优先把它绘制在画布上。如果没有动画了,updatePhysics会通知线程去等待。通常SurfaceView在有两个画布交替绘制的时候,会在画布上绘制上一次......

如果要让你的动态墙纸有配置功能,只要创建一个PreferenceActivity,并将它在wallpaper.xml文件中声明。同时让SharedPreference对象可以找到你的配置选项。

教程就写到这里,如果还有什么不懂,你可以通过Eclipse来浏览完整的源代码:SampleLiveWallpaper。

更多相关文章

  1. Android中的SurfaceView详解
  2. Android(安卓)自定义View——自定义View控件
  3. Android排版和POI
  4. Android学习(18)Canvas_画布(绘图)
  5. Android(安卓)多语言动态切换
  6. 初学Android,增加手势到手势库(五十)
  7. Android(安卓)自定义view组件
  8. Android(安卓)Graphics专题(1)--- Canvas基础
  9. Android(安卓)动态切换全屏和非全屏模式

随机推荐

  1. 教你如何开关Android的APN网络
  2. Android不用OnScrollListener采用Gesture
  3. Android(安卓)TensorFlow 智能语音识别
  4. Android(安卓)WebView 使用漏洞
  5. Android(安卓)AndroidManifest.xml文件的
  6. Android中Market的Loading效果实现方法
  7. 一个快速开发APP的框架:AndroidQuick
  8. Android(安卓)SDK 2.2 开发环境搭建
  9. SE for Android(安卓)系列之整体概要(三)
  10. android连接sql2008