随着三星 Oscar的上市,流畅的操作,华丽的界面,OPhone 2.0的不俗表现不禁让人眼前一亮。作为OPhone 2.0一个新特性,动态壁纸(Live Wallpapers)为用户带来了更炫体验。本文主要通过一个完整的时间壁纸(TimeWall)为大家介绍如何开发 Live Wallpapers。还没开发环境?赶紧去下载OPhone SDK 2.0吧!
1、 Live Wallpapers是什么?
在oscar上有一个动态壁纸叫“天空草地”,用过一段时间,可以发现,随着时间的变化,壁纸的天空就会由蓝蓝青天变成繁星满天。看看效果:
为什么壁纸还有这么神奇的变化,这中间到底是什么在起作用?其实,一个Live Wallpaper就是一个apk!也就是说,动态壁纸的实质是一个apk在后台不断地重绘壁纸,所以我们可以让小草长高,小鸟飞翔。
来看一下AndoridManifest.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <!--
- /*
- **
- ** Copyright 2009, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
- -->
- <manifest
- xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.livecubes">
- <uses-sdk android:minSdkVersion="7" />
- <uses-feature android:name="android.software.live_wallpaper" />
- <application
- android:label="@string/wallpapers"
- android:icon="@drawable/ic_launcher_wallpaper">
- <service
- android:label="@string/wallpaper_cube1"
- android:name=".cube1.CubeWallpaper1"
- 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/cube1" />
- </service>
- <service
- android:label="@string/wallpaper_cube2"
- android:name=".cube2.CubeWallpaper2"
- 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/cube2" />
- </service>
- <activity
- android:label="@string/cube2_settings"
- android:name=".cube2.CubeWallpaper2Settings"
- android:theme="@android:style/Theme.Light.WallpaperSettings"
- android:exported="true">
- </activity>
-
- </application>
- </manifest>
<?xml version="1.0" encoding="utf-8"?> <!-- /* ** ** Copyright 2009, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.livecubes"> <uses-sdk android:minSdkVersion="7" /> <uses-feature android:name="android.software.live_wallpaper" /> <application android:label="@string/wallpapers" android:icon="@drawable/ic_launcher_wallpaper"> <service android:label="@string/wallpaper_cube1" android:name=".cube1.CubeWallpaper1" 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/cube1" /> </service> <service android:label="@string/wallpaper_cube2" android:name=".cube2.CubeWallpaper2" 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/cube2" /> </service> <activity android:label="@string/cube2_settings" android:name=".cube2.CubeWallpaper2Settings" android:theme="@android:style/Theme.Light.WallpaperSettings" android:exported="true"> </activity> <!--android:exported 是否可被其他程序调用 android:permission="android.permission.BIND_WALLPAPER" 桌面服务绑定设置--> </application> </manifest>
原来如此简单,动态壁纸仅仅有一个service就够了。其中
Android :permission="android.permission.BIND_WALLPAPER"
是让该service有能设置为壁纸的权限,没有的话该壁纸只能被预览。
<uses-sdk android:minSdkVersion="7" />
告诉我们,如果你想开发一个live wallpaper,必须是OPhone 2.0或者更高的版本。当然这也需要手机硬件的支持。
2、怎样实现WallpaperService?
WallpaperService与其他的service唯一的不同就是,你必须要增加一个方法onCreateEngine(),它会返回一个 WallpaperService.Engine,这个engine才是负责绘制壁纸以及响应与用户交互事件的核心部件。这个service代码结构如下:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- package com.example.android.livecubes.cube2;
- import android.content.SharedPreferences;
- import android.graphics.Canvas;
- import android.graphics.Paint;
- import android.graphics.Rect;
- import android.os.Handler;
- import android.os.SystemClock;
- import android.service.wallpaper.WallpaperService;
- import android.view.MotionEvent;
- import android.view.SurfaceHolder;
-
-
-
-
-
- public class CubeWallpaper2 extends WallpaperService {
- public static final String SHARED_PREFS_NAME="cube2settings";
- static class ThreeDPoint {
- float x;
- float y;
- float z;
- }
- static class ThreeDLine {
- int startPoint;
- int endPoint;
- }
- @Override
- public void onCreate() {
- super.onCreate();
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- }
- @Override
- public Engine onCreateEngine() {
- return new CubeEngine();
- }
- class CubeEngine extends Engine
- implements SharedPreferences.OnSharedPreferenceChangeListener {
- private final Handler mHandler = new Handler();
- ThreeDPoint [] mOriginalPoints;
- ThreeDPoint [] mRotatedPoints;
- ThreeDLine [] mLines;
- private final Paint mPaint = new Paint();
- private float mOffset;
- private float mTouchX = -1;
- private float mTouchY = -1;
- private long mStartTime;
- private float mCenterX;
- private float mCenterY;
- private final Runnable mDrawCube = new Runnable() {
- public void run() {
- drawFrame();
- }
- };
- private boolean mVisible;
- private SharedPreferences mPrefs;
- CubeEngine() {
-
- final Paint paint = mPaint;
- paint.setColor(0xffffffff);
- paint.setAntiAlias(true);
- paint.setStrokeWidth(2);
- paint.setStrokeCap(Paint.Cap.ROUND);
- paint.setStyle(Paint.Style.STROKE);
- mStartTime = SystemClock.elapsedRealtime();
- mPrefs = CubeWallpaper2.this.getSharedPreferences(SHARED_PREFS_NAME, 0);
- mPrefs.registerOnSharedPreferenceChangeListener(this);
- onSharedPreferenceChanged(mPrefs, null);
- }
- public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
- String shape = prefs.getString("cube2_shape", "cube");
-
- readModel(shape);
- }
- private void readModel(String prefix) {
-
-
- int pid = getResources().getIdentifier(prefix + "points", "array", getPackageName());
- int lid = getResources().getIdentifier(prefix + "lines", "array", getPackageName());
- String [] p = getResources().getStringArray(pid);
- int numpoints = p.length;
- mOriginalPoints = new ThreeDPoint[numpoints];
- mRotatedPoints = new ThreeDPoint[numpoints];
- for (int i = 0; i < numpoints; i++) {
- mOriginalPoints[i] = new ThreeDPoint();
- mRotatedPoints[i] = new ThreeDPoint();
- String [] coord = p[i].split(" ");
- mOriginalPoints[i].x = Float.valueOf(coord[0]);
- mOriginalPoints[i].y = Float.valueOf(coord[1]);
- mOriginalPoints[i].z = Float.valueOf(coord[2]);
- }
- String [] l = getResources().getStringArray(lid);
- int numlines = l.length;
- mLines = new ThreeDLine[numlines];
- for (int i = 0; i < numlines; i++) {
- mLines[i] = new ThreeDLine();
- String [] idx = l[i].split(" ");
- mLines[i].startPoint = Integer.valueOf(idx[0]);
- mLines[i].endPoint = Integer.valueOf(idx[1]);
- }
- }
- @Override
- public void onCreate(SurfaceHolder surfaceHolder) {
- super.onCreate(surfaceHolder);
- setTouchEventsEnabled(true);
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- mHandler.removeCallbacks(mDrawCube);
- }
- @Override
- public void onVisibilityChanged(boolean visible) {
- mVisible = visible;
- if (visible) {
- drawFrame();
- } else {
- mHandler.removeCallbacks(mDrawCube);
- }
- }
- @Override
- public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- super.onSurfaceChanged(holder, format, width, height);
-
- mCenterX = width/2.0f;
- mCenterY = height/2.0f;
- drawFrame();
- }
- @Override
- public void onSurfaceCreated(SurfaceHolder holder) {
- super.onSurfaceCreated(holder);
- }
- @Override
- public void onSurfaceDestroyed(SurfaceHolder holder) {
- super.onSurfaceDestroyed(holder);
- mVisible = false;
- mHandler.removeCallbacks(mDrawCube);
- }
- @Override
- public void onOffsetsChanged(float xOffset, float yOffset,
- float xStep, float yStep, int xPixels, int yPixels) {
- mOffset = xOffset;
- drawFrame();
- }
-
-
-
- @Override
- public void onTouchEvent(MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_MOVE) {
- mTouchX = event.getX();
- mTouchY = event.getY();
- } else {
- mTouchX = -1;
- mTouchY = -1;
- }
- super.onTouchEvent(event);
- }
-
-
-
-
-
- void drawFrame() {
- final SurfaceHolder holder = getSurfaceHolder();
- final Rect frame = holder.getSurfaceFrame();
- final int width = frame.width();
- final int height = frame.height();
- Canvas c = null;
- try {
- c = holder.lockCanvas();
- if (c != null) {
-
- drawCube(c);
- drawTouchPoint(c);
- }
- } finally {
- if (c != null) holder.unlockCanvasAndPost(c);
- }
- mHandler.removeCallbacks(mDrawCube);
- if (mVisible) {
- mHandler.postDelayed(mDrawCube, 1000 / 25);
- }
- }
- void drawCube(Canvas c) {
- c.save();
- c.translate(mCenterX, mCenterY);
- c.drawColor(0xff000000);
- long now = SystemClock.elapsedRealtime();
- float xrot = ((float)(now - mStartTime)) / 1000;
- float yrot = (0.5f - mOffset) * 2.0f;
- rotateAndProjectPoints(xrot, yrot);
- drawLines(c);
- c.restore();
- }
- void rotateAndProjectPoints(float xrot, float yrot) {
- int n = mOriginalPoints.length;
- for (int i = 0; i < n; i++) {
-
- ThreeDPoint p = mOriginalPoints[i];
- float x = p.x;
- float y = p.y;
- float z = p.z;
- float newy = (float)(Math.sin(xrot) * z + Math.cos(xrot) * y);
- float newz = (float)(Math.cos(xrot) * z - Math.sin(xrot) * y);
-
- float newx = (float)(Math.sin(yrot) * newz + Math.cos(yrot) * x);
- newz = (float)(Math.cos(yrot) * newz - Math.sin(yrot) * x);
-
- float screenX = newx / (4 - newz / 400);
- float screenY = newy / (4 - newz / 400);
- mRotatedPoints[i].x = screenX;
- mRotatedPoints[i].y = screenY;
- mRotatedPoints[i].z = 0;
- }
- }
- void drawLines(Canvas c) {
- int n = mLines.length;
- for (int i = 0; i < n; i++) {
- ThreeDLine l = mLines[i];
- ThreeDPoint start = mRotatedPoints[l.startPoint];
- ThreeDPoint end = mRotatedPoints[l.endPoint];
- c.drawLine(start.x, start.y, end.x, end.y, mPaint);
- }
- }
- void drawTouchPoint(Canvas c) {
- if (mTouchX >=0 && mTouchY >= 0) {
- c.drawCircle(mTouchX, mTouchY, 80, mPaint);
- }
- }
- }
- }
/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.livecubes.cube2; import android.content.SharedPreferences; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.os.Handler; import android.os.SystemClock; import android.service.wallpaper.WallpaperService; import android.view.MotionEvent; import android.view.SurfaceHolder; /* * This animated wallpaper draws a rotating wireframe shape. It is similar to * example #1, but has a choice of 2 shapes, which are user selectable and * defined in resources instead of in code. */ public class CubeWallpaper2 extends WallpaperService { public static final String SHARED_PREFS_NAME="cube2settings"; static class ThreeDPoint { float x; float y; float z; } static class ThreeDLine { int startPoint; int endPoint; } @Override public void onCreate() { super.onCreate(); } @Override public void onDestroy() { super.onDestroy(); } @Override public Engine onCreateEngine() { return new CubeEngine(); } class CubeEngine extends Engine implements SharedPreferences.OnSharedPreferenceChangeListener { private final Handler mHandler = new Handler(); ThreeDPoint [] mOriginalPoints; ThreeDPoint [] mRotatedPoints; ThreeDLine [] mLines; private final Paint mPaint = new Paint(); private float mOffset; private float mTouchX = -1; private float mTouchY = -1; private long mStartTime; private float mCenterX; private float mCenterY; private final Runnable mDrawCube = new Runnable() { public void run() { drawFrame(); } }; private boolean mVisible; private SharedPreferences mPrefs; CubeEngine() { // Create a Paint to draw the lines for our cube final Paint paint = mPaint; paint.setColor(0xffffffff); paint.setAntiAlias(true); paint.setStrokeWidth(2); paint.setStrokeCap(Paint.Cap.ROUND); paint.setStyle(Paint.Style.STROKE); mStartTime = SystemClock.elapsedRealtime(); mPrefs = CubeWallpaper2.this.getSharedPreferences(SHARED_PREFS_NAME, 0); mPrefs.registerOnSharedPreferenceChangeListener(this); onSharedPreferenceChanged(mPrefs, null); } public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { String shape = prefs.getString("cube2_shape", "cube"); // read the 3D model from the resource readModel(shape); } private void readModel(String prefix) { // Read the model definition in from a resource. // get the resource identifiers for the arrays for the selected shape int pid = getResources().getIdentifier(prefix + "points", "array", getPackageName()); int lid = getResources().getIdentifier(prefix + "lines", "array", getPackageName()); String [] p = getResources().getStringArray(pid); int numpoints = p.length; mOriginalPoints = new ThreeDPoint[numpoints]; mRotatedPoints = new ThreeDPoint[numpoints]; for (int i = 0; i < numpoints; i++) { mOriginalPoints[i] = new ThreeDPoint(); mRotatedPoints[i] = new ThreeDPoint(); String [] coord = p[i].split(" "); mOriginalPoints[i].x = Float.valueOf(coord[0]); mOriginalPoints[i].y = Float.valueOf(coord[1]); mOriginalPoints[i].z = Float.valueOf(coord[2]); } String [] l = getResources().getStringArray(lid); int numlines = l.length; mLines = new ThreeDLine[numlines]; for (int i = 0; i < numlines; i++) { mLines[i] = new ThreeDLine(); String [] idx = l[i].split(" "); mLines[i].startPoint = Integer.valueOf(idx[0]); mLines[i].endPoint = Integer.valueOf(idx[1]); } } @Override public void onCreate(SurfaceHolder surfaceHolder) { super.onCreate(surfaceHolder); setTouchEventsEnabled(true); } @Override public void onDestroy() { super.onDestroy(); mHandler.removeCallbacks(mDrawCube); } @Override public void onVisibilityChanged(boolean visible) { mVisible = visible; if (visible) { drawFrame(); } else { mHandler.removeCallbacks(mDrawCube); } } @Override public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { super.onSurfaceChanged(holder, format, width, height); // store the center of the surface, so we can draw the cube in the right spot mCenterX = width/2.0f; mCenterY = height/2.0f; drawFrame(); } @Override public void onSurfaceCreated(SurfaceHolder holder) { super.onSurfaceCreated(holder); } @Override public void onSurfaceDestroyed(SurfaceHolder holder) { super.onSurfaceDestroyed(holder); mVisible = false; mHandler.removeCallbacks(mDrawCube); } @Override public void onOffsetsChanged(float xOffset, float yOffset, float xStep, float yStep, int xPixels, int yPixels) { mOffset = xOffset; drawFrame(); } /* * Store the position of the touch event so we can use it for drawing later */ @Override public void onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_MOVE) { mTouchX = event.getX(); mTouchY = event.getY(); } else { mTouchX = -1; mTouchY = -1; } super.onTouchEvent(event); } /* * Draw one frame of the animation. This method gets called repeatedly * by posting a delayed Runnable. You can do any drawing you want in * here. This example draws a wireframe cube. */ void drawFrame() { final SurfaceHolder holder = getSurfaceHolder(); final Rect frame = holder.getSurfaceFrame(); final int width = frame.width(); final int height = frame.height(); Canvas c = null; try { c = holder.lockCanvas(); if (c != null) { // draw something drawCube(c); drawTouchPoint(c); } } finally { if (c != null) holder.unlockCanvasAndPost(c); } mHandler.removeCallbacks(mDrawCube); if (mVisible) { mHandler.postDelayed(mDrawCube, 1000 / 25); } } void drawCube(Canvas c) { c.save(); c.translate(mCenterX, mCenterY); c.drawColor(0xff000000); long now = SystemClock.elapsedRealtime(); float xrot = ((float)(now - mStartTime)) / 1000; float yrot = (0.5f - mOffset) * 2.0f; rotateAndProjectPoints(xrot, yrot); drawLines(c); c.restore(); } void rotateAndProjectPoints(float xrot, float yrot) { int n = mOriginalPoints.length; for (int i = 0; i < n; i++) { // rotation around X-axis ThreeDPoint p = mOriginalPoints[i]; float x = p.x; float y = p.y; float z = p.z; float newy = (float)(Math.sin(xrot) * z + Math.cos(xrot) * y); float newz = (float)(Math.cos(xrot) * z - Math.sin(xrot) * y); // rotation around Y-axis float newx = (float)(Math.sin(yrot) * newz + Math.cos(yrot) * x); newz = (float)(Math.cos(yrot) * newz - Math.sin(yrot) * x); // 3D-to-2D projection float screenX = newx / (4 - newz / 400); float screenY = newy / (4 - newz / 400); mRotatedPoints[i].x = screenX; mRotatedPoints[i].y = screenY; mRotatedPoints[i].z = 0; } } void drawLines(Canvas c) { int n = mLines.length; for (int i = 0; i < n; i++) { ThreeDLine l = mLines[i]; ThreeDPoint start = mRotatedPoints[l.startPoint]; ThreeDPoint end = mRotatedPoints[l.endPoint]; c.drawLine(start.x, start.y, end.x, end.y, mPaint); } } void drawTouchPoint(Canvas c) { if (mTouchX >=0 && mTouchY >= 0) { c.drawCircle(mTouchX, mTouchY, 80, mPaint); } } } }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- package com.example.android.livecubes.cube2;
- import com.example.android.livecubes.R;
- import android.content.SharedPreferences;
- import android.os.Bundle;
- import android.preference.PreferenceActivity;
- public class CubeWallpaper2Settings extends PreferenceActivity
- implements SharedPreferences.OnSharedPreferenceChangeListener {
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- getPreferenceManager().setSharedPreferencesName(
- CubeWallpaper2.SHARED_PREFS_NAME);
- addPreferencesFromResource(R.xml.cube2_settings);
- getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(
- this);
- }
- @Override
- protected void onResume() {
- super.onResume();
- }
- @Override
- protected void onDestroy() {
- getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(
- this);
- super.onDestroy();
- }
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
- String key) {
- }
- }
/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.example.android.livecubes.cube2; import com.example.android.livecubes.R; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceActivity; public class CubeWallpaper2Settings extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener { @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); getPreferenceManager().setSharedPreferencesName( CubeWallpaper2.SHARED_PREFS_NAME); addPreferencesFromResource(R.xml.cube2_settings); getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener( this); } @Override protected void onResume() { super.onResume(); } @Override protected void onDestroy() { getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener( this); super.onDestroy(); } public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { } }
类TimeEngine才是处理壁纸的核心类,我们会在类TimeEngine中加上自己的逻辑以完成壁纸的绘制、变化以及销毁。Engine的生命周期与大多数OPhone应用程序 组件,比如activity类似,都是从onCreate()开始,在销毁时调用onDestory()方法。不同的是WallpaperService会提供一个surface用来绘制壁纸,所以在生命周期中多一个onSurfaceCreated与onSurfaceDestroyed的过程。下面是一个最简生命周期:
也就是说只要我们实现上面四个方法,一个基本的LiveWallpaper就可以完成了。让我们逐个看一下这几个方法的实现。
nCreate方法里,我们
setTouchEventsEnabled(true);
作用是使壁纸能响应touch event,默认是false。TimeWall会在用户点击屏幕的时候画一个十字架,所以我们需要设置其为true。
可以看到我们在这四个方法里面做的事情非常简单,就是在create时候发一个message,执行画面的绘制,在destory时remove这个消息。
从上面可以看出,动态壁纸实际上就是不断刷新的静态壁纸,越华丽越流畅,CPU就消耗越大,对于现在的本来电量就不怎么地的智能机来说,耗电也是很可观的。但是偶尔向朋友们炫一下还是绝对可行的。drawTime()与 drawCross()的内容可以由家自己实现,在TimeWall里,它们比较简单。drawTime()是计算下一处Time String应该移动到的坐标,以及画出这个String。drawCross()的作用是在用户触发onTouchEvent时画一个十字架。因为 TimeWall比较简单,如果大家自己实现的画图比较复杂,可以另外开启一个线程来刷新UI ,否则有可能主线程被阻塞掉。
cube2.xml
- <wallpaper xmlns:android="http://schemas.android.com/apk/res/android"
- android:settingsActivity="com.example.android.livecubes.cube2.CubeWallpaper2Settings"
- />
<wallpaper xmlns:android="http://schemas.android.com/apk/res/android" android:settingsActivity="com.example.android.livecubes.cube2.CubeWallpaper2Settings" />
cube2_setting
- <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
- android:title="@string/cube2_settings"
- android:key="cube2wallpaper_settings">
- <ListPreference
- android:key="cube2_shape"
- android:title="@string/cube2_settings_title"
- android:summary="@string/cube2_settings_summary"
- android:entries="@array/cube2_shapenames"
- android:entryValues="@array/cube2_shapeprefix" />
- </PreferenceScreen>