动态壁纸

Livewallpaper(动态壁纸): 首先动态壁纸并不是GIF图片,而是一个独立的应用程序,本质是一个Service,甚至可以没有桌面图标。


直接看AndroidManifest.xml

<?xml version="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">                        

clock_wallpaper.xml

<?xml version="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动态壁纸详解_第1张图片

android:settingsActivity 指定一个Activity。系统会检测动态壁纸应用有没有此属性。如果有则和下方的图片显示效果一样(两个Button),点击下图中设定Button可跳转至指定的Activity(设置界面)。如果没有此属性,就只有一个设置壁纸Button。可以去掉此属性看一下效果。
Android动态壁纸详解_第2张图片


WallpaperService(核心)

实现动态壁纸必须继承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");        }    }}

ClockView(钟表的具体绘制)

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);          }        }    }}

更多相关文章

  1. android实现动态更换应用图标
  2. Android ViewPager实现Tabhost选项卡底部滑块动态滑动过渡
  3. Android 进阶——Material Design新控件之AppBarLayout+Toolbar+
  4. Android动态分析工具Inspeckage
  5. Android 10.0 Andorid.bp 动态编译模块
  6. 【Android高级】DexClassloader和PathClassloader动态加载插件的
  7. Android 中关于PathEffect子类的效果(中级)
  8. Android下动态链接库.so调用的简单例子

随机推荐

  1. Android(安卓)ApiDemos示例解析(73):Grap
  2. Android(安卓)- 资源(resource)
  3. Android(安卓)studio aar文件的打包过程
  4. Android原生音量控制实例详解
  5. ContentProvider 详解
  6. [Android]View响应屏幕触摸事件
  7. Android各框架的总结及选型
  8. ym——Android之常用Tools【介绍及使用】
  9. [置顶] android 深入理解AnsyncTask
  10. Android(安卓)Service两种启动启动方式