Livewallpaper(动态壁纸): 首先动态壁纸并不是GIF图片,而是一个独立的应用程序,本质是一个Service,甚至可以没有桌面图标。
"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
package="com.qwq.clocklivewallpaper">
"true"
android:icon="@drawable/clock"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
".MainActivity">
"android.intent.action.MAIN" />
"android.intent.category.LAUNCHER" />
".SettingsActivity"
android:exported="true"
android:label="@string/app_name">
".ClockWallpaperService"
android:enabled="true"
android:label="@string/wallpaper_name" //下面第一张图片中label
android:permission="android.permission.BIND_WALLPAPER">//动态壁纸必须加此权限
//系统就是通过APK的这个action把其当做一个动态墙纸。
"android.service.wallpaper.WallpaperService">
"android.service.wallpaper"
android:resource="@xml/clock_wallpaper">
"1.0" encoding="UTF-8"?>
"http://schemas.android.com/apk/res/android"
android:description="@string/wallpaper_description"
android:settingsActivity="com.qwq.clocklivewallpaper.SettingsActivity"
android:thumbnail="@drawable/ic_preview" />
android:thumbnail 动态壁纸列表中的图标,
android:description 动态壁纸的简单介绍文字,有的手机可能不显示
android:settingsActivity 指定一个Activity。系统会检测动态壁纸应用有没有此属性。如果有则和下方的图片显示效果一样(两个Button),点击下图中设定Button可跳转至指定的Activity(设置界面)。如果没有此属性,就只有一个设置壁纸Button。可以去掉此属性看一下效果。
实现动态壁纸必须继承WallpaperService,且重载onCreateEngine方法。onCreateEngine()方法只需返回一个Engine的子类对象就可以了,所以动态壁纸应用的主要工作就是实现Engine的子类。其原理是使用surfaceview不断更新,实现动态壁纸效果。不多说了,直接贴代码,重要的方法都会有所说明。
package com.qwq.clocklivewallpaper;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import java.util.Date;
public class ClockWallpaperService extends WallpaperService {
static final String TAG = ClockWallpaperService.class.getSimpleName();
static final int POINTER_WIDTH = 9;
// onCreateEngine()方法需返回一个Engine的子类对象就可以了,
// 所以动态壁纸应用的主要工作就是实现Engine的子类
@Override
public Engine onCreateEngine() {
Log.d(TAG, "onCreateEngine");
return new ClockWallpaperEngine();
}
//实现Engine的子类,本文的重中之重,动态壁纸就是在此具体实现的
private class ClockWallpaperEngine extends Engine implements
OnSharedPreferenceChangeListener {
private final Handler handler = new Handler();
// surfacewive使用线程更新UI,所以我们可使用Runnable接口创建一个线程,把具体绘制方法放进去,
// 下文会使用handler调用
private final Runnable drawRunner = new Runnable() {
@Override
public void run() {
draw();
}
};
private Paint paint;
private int width;
private int height;
private boolean isVisible = true;
private boolean isShowSecond;
private ClockView clockView;
private SharedPreferences sp;
//构造函数,初始化动态壁纸
public ClockWallpaperEngine() {
Log.d(TAG, "ClockWallpaperEngine");
initSp();
initPaint();
startDrawClock();
}
public void initSp() {
sp = PreferenceManager.getDefaultSharedPreferences(ClockWallpaperService.this);
sp.registerOnSharedPreferenceChangeListener(this);
isShowSecond = sp.getBoolean(SettingsActivity.IS_SHOW_SECOND, true);
}
public void initPaint() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(POINTER_WIDTH);
}
public void startDrawClock() {
clockView = new ClockView(getApplicationContext());
handler.post(drawRunner);
}
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
Log.d(TAG, "onCreate");
}
//监听是否可见变化,可见时开始更新UI,不可见时停止刷新
@Override
public void onVisibilityChanged(boolean visible) {
this.isVisible = visible;
if (visible) {
handler.post(drawRunner);
} else {
handler.removeCallbacks(drawRunner);
}
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
isVisible = false;
handler.removeCallbacks(drawRunner);
sp.unregisterOnSharedPreferenceChangeListener(this);
}
@Override
public void onSurfaceChanged(SurfaceHolder holder,int format,int width,int height){
this.width = width;
this.height = height;
super.onSurfaceChanged(holder, format, width, height);
}
//绘制,每个200毫秒刷新界面
private void draw() {
SurfaceHolder holder = getSurfaceHolder();
Canvas canvas = null;
try {
canvas = holder.lockCanvas();
if (canvas != null) {
drawClock(canvas);
}
} finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
handler.removeCallbacks(drawRunner);
if (isVisible) {
handler.postDelayed(drawRunner, 200);
}
}
//具体绘制钟表
private void drawClock(Canvas canvas) {
canvas.drawColor(Color.WHITE); //绘制整个动态壁纸的背景颜色
clockView.config(width / 2, height / 2, (int) (width * 0.8f), new Date(),
paint, isShowSecond);
clockView.draw(canvas);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String
key){
//监听SharedPreference变化,改变动态壁纸样式
if (SettingsActivity.IS_SHOW_SECOND.equals(key)) {
isShowSecond = sharedPreferences.getBoolean(SettingsActivity.IS_SHOW_SECOND,
true);
}
}
@Override
public void onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
// 可以在这里做一些与用户交互的操作,例如动态星星壁纸,用户触摸屏幕时增加星星数量。
Log.d(TAG, "onTouchEvent");
}
}
}
package com.qwq.clocklivewallpaper;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.View;
import java.util.Calendar;
import java.util.Date;
public class ClockView extends View {
static final String TAG = ClockView.class.getSimpleName();
private float x;
private float y;
private int radius;
private Calendar cal;
private Paint paint;
private Bitmap clockDial = BitmapFactory.decodeResource(getResources(),R.drawable.clock_bg);
private int sizeScaled = -1;
private Bitmap clockDialScaled;
private boolean isShowSecond;
public ClockView(Context context) {
super(context);
cal = Calendar.getInstance();
}
//设置钟表宽高等属性
public void config(float x, float y, int size, Date date, Paint paint, boolean
isShowSecond) {
this.x = x;
this.y = y;
this.paint = paint;
this.isShowSecond = isShowSecond;
cal.setTime(date);
if (size != sizeScaled) {
clockDialScaled = Bitmap.createScaledBitmap(clockDial, size, size, false);
radius = size / 2;
}
}
//具体绘制钟表的指针
protected void onDraw(Canvas canvas) {
Log.d(TAG,"onDraw:"+canvas);
super.onDraw(canvas);
if (paint != null) {
canvas.drawBitmap(clockDialScaled, x - radius, y - radius, null);
float sec = cal.get(Calendar.SECOND);
float min = cal.get(Calendar.MINUTE);
float hour = cal.get(Calendar.HOUR_OF_DAY);
paint.setColor(Color.RED);
canvas.drawLine(x, y,
(float)(x + (radius * 0.5f)*Math.cos(Math.toRadians((hour / 12.0f * 360.0f) - 90f))),
(float)(y + (radius * 0.5f)*Math.sin(Math.toRadians((hour / 12.0f * 360.0f) -90f))),
paint);
canvas.save();
paint.setColor(Color.BLUE);
canvas.drawLine(x, y,
(float)(x + (radius * 0.6f)*Math.cos(Math.toRadians((min / 60.0f * 360.0f) - 90f))),
(float)(y + (radius * 0.6f)*Math.sin(Math.toRadians((min / 60.0f * 360.0f) - 90f))),
paint);
canvas.save();
if (isShowSecond) {
paint.setColor(Color.GREEN);
canvas.drawLine(x, y,
(float)(x + (radius * 0.7f)*Math.cos(Math.toRadians((sec/60.0f * 360.0f) - 90f))),
(float)(y + (radius * 0.7f)*Math.sin(Math.toRadians((sec/60.0f * 360.0f) - 90f))),
paint);
}
}
}
}