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)的方法,這里雖然實現的代碼較少,但效率較低,畫面仍不夠流暢.