Android Launcher開發之動態壁紙(LiveWallPaper)氣泡流動效果
最近在研究Laucher應用,今天寫了一下四組件中的壁紙(WallPaper),關于靜態壁紙的實現,比較簡單,在此就不再描述. 參考了系統源代碼之后,我自己做了一個簡單的動態壁紙:氣泡流動效果. 圖案比較簡單,但基本原理可在此例子上加以擴展,比如3D動畫效果,復雜的觸摸改變動畫事件,有興趣的朋友可以試一試.
大概效果如下,最開始得時候,會從四個角落的方向浮出四個氣泡,然后以一定的路線移動,當移出屏幕時重新開始以新的坐標浮出,以此實現了一個簡單的氣泡浮動的效果:
實現的思路 :
1、新建一個Android工程 ,注意,對于Live Wallpaper來說傳統的布局文件是不需要的。
2、在res下面新建一個xml文件夾 然后新建一個livewallpaper.xml 內容如下:
<?xml version="1.0" encoding="utf-8"?> <wallpaper xmlns:android="http://schemas.android.com/apk/res/android" android:thumbnail="@drawable/icon"/>
注意: 這里的android:thumbnail值得是你這個動態壁紙的小圖標 會在你選著動態壁紙的時候出現,也可以不寫此屬性
3. 實現動態壁紙是不需要使用Activity, 創建LiveWallpaper類,讓其繼承WallpaperService:
實現 onCreateEngine()方法,返回自己實現的Engine類
在Engine類中的onCreate()方法中進行調用繪制圖形的drawFrame()方法
定義四個圓形的起始坐標,每次調用drawFrame()時改變圓形的坐標,通過mHandler.postDelayed(drawTarget, 100);方法,進行重新繪制圖形,更新UI
具體代碼如下:
1.AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.crazyit.desktop" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <!-- 配置實時壁紙Service --> <service android:label="@string/app_name" android:name=".LiveWallpaper" android:permission="android.permission.BIND_WALLPAPER"> <!-- 為實時壁紙配置intent-filter --> <intent-filter> <action android:name="android.service.wallpaper.WallpaperService" /> </intent-filter> <!-- 為實時壁紙配置meta-data --> <meta-data android:name="android.service.wallpaper" android:resource="@xml/livewallpaper" /> </service> </application> </manifest>
2. 壁紙的xml文件: livewallpaper.xml
<?xml version="1.0" encoding="utf-8"?> <wallpaper xmlns:android="http://schemas.android.com/apk/res/android" android:thumbnail="@drawable/icon"/>
3. 實現動態壁紙的LiveWallpaper類:
import android.graphics.Canvas; import android.graphics.Paint; import android.os.Handler; import android.service.wallpaper.WallpaperService; import android.view.MotionEvent; import android.view.SurfaceHolder; /** * * @author Tian * */ public class LiveWallpaper extends WallpaperService { // 實現WallpaperService必須實現的抽象方法 public Engine onCreateEngine() { // 返回自定義的Engine return new MyEngine(); } class MyEngine extends Engine { // 記錄程序界面是否可見 private boolean mVisible; // 記錄當前當前用戶動作事件的發生位置 private float mTouchX = -1; private float mTouchY = -1; // 記錄當前圓圈的繪制位置 //左上角坐標 private float cx1 = 15; private float cy1 = 20; //右下角坐標 private float cx2 = 300; private float cy2 = 380; //右上角坐標 private float cx3 = 300; private float cy3 = 20; //左下角坐標 private float cx4 = 15; private float cy4 = 380; // 定義畫筆 private Paint mPaint = new Paint(); // 定義一個Handler Handler mHandler = new Handler(); // 定義一個周期性執行的任務 private final Runnable drawTarget = new Runnable() { public void run() { // 動態地繪制圖形 drawFrame(); } }; @Override public void onCreate(SurfaceHolder surfaceHolder) { super.onCreate(surfaceHolder); // 初始化畫筆 mPaint.setColor(0xffffffff); mPaint.setAntiAlias(true); mPaint.setStrokeWidth(2); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStyle(Paint.Style.STROKE); // 設置處理觸摸事件 setTouchEventsEnabled(true); } @Override public void onDestroy() { super.onDestroy(); // 刪除回調 mHandler.removeCallbacks(drawTarget); } @Override public void onVisibilityChanged(boolean visible) { mVisible = visible; // 當界面可見時候,執行drawFrame()方法。 if (visible) { // 動態地繪制圖形 drawFrame(); } else { // 如果界面不可見,刪除回調 mHandler.removeCallbacks(drawTarget); } } public void onOffsetsChanged(float xOffset, float yOffset, float xStep, float yStep, int xPixels, int yPixels) { drawFrame(); } 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); } // 定義繪制圖形的工具方法 private void drawFrame() { // 獲取該壁紙的SurfaceHolder final SurfaceHolder holder = getSurfaceHolder(); Canvas c = null; try { // 對畫布加鎖 c = holder.lockCanvas(); if (c != null) { c.save(); // 繪制背景色 c.drawColor(0xff000000); // 在觸碰點繪制圓圈 drawTouchPoint(c); // 繪制圓圈 c.drawCircle(cx1, cy1, 80, mPaint); c.drawCircle(cx2, cy2, 40, mPaint); c.drawCircle(cx3, cy3, 50, mPaint); c.drawCircle(cx4, cy4, 60, mPaint); c.restore(); } } finally { if (c != null) holder.unlockCanvasAndPost(c); } mHandler.removeCallbacks(drawTarget); // 調度下一次重繪 if (mVisible) { cx1 += 6; cy1 += 8; // 如果cx1、cy1移出屏幕后從左上角重新開始 if (cx1 > 320) cx1 = 15; if (cy1 > 400) cy1 = 20; cx2 -= 6; cy2 -= 8; // 如果cx2、cy2移出屏幕后從右下角重新開始 if (cx2 <15) cx2 = 300; if (cy2 <20) cy2 = 380; cx3 -= 6; cy3 += 8; // 如果cx3、cy3移出屏幕后從右上角重新開始 if (cx3 <0) cx3 = 300; if (cy3 >400) cy3 = 20; cx4 += 6; cy4 -= 8; // 如果cx4、cy4移出屏幕后從左下角重新開始 if (cx4 >320) cx4 = 15; if (cy4 <0) cy4 = 380; // 指定0.1秒后重新執行mDrawCube一次 mHandler.postDelayed(drawTarget, 100); } } // 在屏幕觸碰點繪制圓圈 private void drawTouchPoint(Canvas c) { if (mTouchX >= 0 && mTouchY >= 0) { c.drawCircle(mTouchX, mTouchY, 40, mPaint); } } } }
這樣,就基本實現了一個動態壁紙:氣泡浮動的效果.
不過這只是一個入門的小例子,如果想達到商用效果,還有很多方面需要進行優化:
1. 繪制更加復雜的圖形
2. 使用3D Animation動畫效果
3. 色彩方面需要豐富起來
4. 更新UI的方法我使用了handler的postDelay(runnable,millsecond)的方法,這里雖然實現的代碼較少,但效率較低,畫面仍不夠流暢.