下面以一個範例來實作一個簡單的動態桌布,桌布背景為黑色, 當使用者點擊或劃過桌布時,會產生藍色的圓,並且隨時間變小消失:
- 建立WallpaperService。動態桌布其實也是一種Service,使用的class為WallpaperService,所以我們要先建立WallpaperService類別,程式碼如下,需要注意的是,在WallpaperService裡的Engine內部類別不行在WallpaperService之外建立然後使用,必須是也內部類別的方式存在在WallpaperService中:
- 建立給WallpaperService的資訊xml檔。其中可以指定縮圖(thumbnail)、簡介(description)等,配置內容如下:
- 註冊WallpaperService。因為WallpaperService是一種Service,所以要在AndroidManifest.xml中的<Application>節點中添加Service的注冊,如下程式碼,有幾點要注意,在Service中要加入"android.permission.BIND_WALLPAPER"並設定<intent-filter>的<action>為"android.service.wallpaper.WallpaperService"、還要加入相關的<meta-data>並在其中指定動態桌步的資訊xml檔,即上步驟的wallpaperinfo.xml:
- 建立Engine要用的Thread類別。 WallpaperThread.java:
- 最後的成品如下面影片展示:
MyWallpaperService.java:
package com.example.administrator.wallpaperservice_example; import android.service.wallpaper.WallpaperService; import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceHolder; public class MyWallpaperService extends WallpaperService{ @Override public Engine onCreateEngine() { return new MyEngine(); } //設定自訂的Engine class MyEngine extends Engine{ WallpaperThread wallpaperThread; public MyEngine() { SurfaceHolder surfaceHolder = getSurfaceHolder(); wallpaperThread = new WallpaperThread(surfaceHolder); } @Override public void onCreate(SurfaceHolder surfaceHolder) { super.onCreate(surfaceHolder); //設定動態桌布可以互動觸控事件 setTouchEventsEnabled(true); } @Override public void onSurfaceCreated(SurfaceHolder holder) { super.onSurfaceCreated(holder); //開始執行動態桌布 wallpaperThread.start(); } @Override public void onSurfaceDestroyed(SurfaceHolder holder) { super.onSurfaceDestroyed(holder); //結束動態桌布 wallpaperThread.stopRunning(); } @Override public void onDestroy() { super.onDestroy(); //讓GC回收wallpaperThread wallpaperThread = null; } @Override public void onTouchEvent(MotionEvent event) { super.onTouchEvent(event); //執行wallpaperThread裡的觸控事件 wallpaperThread.doTouchEvent(event); } } }
wallpaperinfo.xml:
<?xml version="1.0" encoding="utf-8"?> <wallpaper xmlns:android="http://schemas.android.com/apk/res/android"> xmlns:android="http://schemas.android.com/apk/res/android" android:description="動態桌布" </wallpaper>
AndroidManifest.xml的片段:
<service android:name=".MyWallpaperService" 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/wallpaperinfo" /> </service>
package com.example.administrator.wallpaperservice_example; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceHolder; import java.util.ArrayList; public class WallpaperThread extends Thread { //run為ture表示不斷檢查並執行消圓動作 boolean run = true; //wait為true表示無圓可消,所以暫停消圓動作 boolean wait = true; //SurfaceHolder用來取得Canvas SurfaceHolder surfaceHolder; Canvas canvas; Paint paint; //用來紀錄已產生的圓資料,待處理 ArrayList<Circle> pastCircles = new ArrayList<>(); //用來紀錄要從pastCircles中刪去的圓資料,因為不能在ArrayList遍歷元素時刪除元素,否則會有ConcurrentModificationException ArrayList<Circle> circlesToBeRemoved = new ArrayList<>(); public WallpaperThread(SurfaceHolder surfaceHolder) { this.surfaceHolder = surfaceHolder; //設定畫圓用的畫筆顏色 paint = new Paint(); paint.setColor(Color.BLUE); } @Override public void run() { canvas = this.surfaceHolder.lockCanvas(null); //繪製初始背景 canvas.drawColor(Color.BLACK); surfaceHolder.unlockCanvasAndPost(canvas); while (run) { if (wait) { try { synchronized (this) { //沒有圓可消時,讓Thread等待 wait(); } } catch (InterruptedException e) { e.printStackTrace(); } } else { synchronized (pastCircles) { //將圓刪掉(背景重新塗色) canvas = surfaceHolder.lockCanvas(null); canvas.drawColor(Color.BLACK); //檢查pastCircles中有無待處理的圓 for (Circle circle : pastCircles) { //如果圓的半徑已被減0以下,就將其從pastCircles中刪除 if (circle.getRadius() <= 0) { circlesToBeRemoved.add(circle); } else { //畫圓 canvas.drawCircle(circle.getCenterX(), circle.getCenterY(), circle.getRadius(), paint); //將圓半徑減1 circle.setRadius(circle.getRadius() - 1); } } surfaceHolder.unlockCanvasAndPost(canvas); //從pastCircles中刪去已消完的圓資料 pastCircles.removeAll(circlesToBeRemoved); //如果pastCircles中沒有圓了,就進行等待 wait = (pastCircles.size() == 0); } } } } public void stopRunning() { run = false; } public void doTouchEvent(MotionEvent motionEvent) { //判斷Touch動作 switch (motionEvent.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: //用來紀錄觸控動作發生時相應的圓圈資訊 Circle currentCircle = new Circle(motionEvent.getX(), motionEvent.getY(), 100); //保護pastCircles,避免跟run()中讀取pastCircles的動作起衡突 synchronized (pastCircles) { //將要處理的的圓紀錄到pastCircles中 pastCircles.add(currentCircle); wait = false; synchronized (this) { //主動喚醒Thread notify(); } } break; } } //用來紀錄圓的資訊 class Circle { float centerX; float centerY; int radius = 100; public Circle(float centerX, float centerY, int radius) { this.centerX = centerX; this.centerY = centerY; this.radius = radius; } public void setRadius(int radius) { this.radius = radius; } public float getCenterX() { return centerX; } public float getCenterY() { return centerY; } public int getRadius() { return radius; } } }
附上源始碼下載: Android動態桌布.7z
感謝 晚點立刻測試!!!
回覆刪除您好,想請問大大如何把動態桌布的黑底改成自定圖片?
回覆刪除您可以使用canvas.drawBitmap()代替canvas.drawColor()來繪製您要的圖片。
刪除