"Android項目刮刮獎詳解(三)" 前言 上一期我們已經是完成了刮刮卡的基本功能,本期就是給我們的項目增加個功能以及美化一番 目標 + 增加功能 用戶刮卡刮到一定程度的時候,清除遮蓋層 + 在遮蓋層放張圖片,增加用戶體驗 + 增加一個刮完獎回調監聽 實現 1.自動消除效果 我們首先來瞭解一下bi ...
前言
上一期我們已經是完成了刮刮卡的基本功能,本期就是給我們的項目增加個功能以及美化一番
目標
- 增加功能 用戶刮卡刮到一定程度的時候,清除遮蓋層
- 在遮蓋層放張圖片,增加用戶體驗
增加一個刮完獎回調監聽
實現
1.自動消除效果
我們首先來瞭解一下bitmap的
getPixels
方法getPixels(@ColorInt int[] pixels, int offset, int stride,int x, int y, int width, int height)
getPixels()函數把一張圖片,從指定的偏移位置(offset),指定的位置(x,y)截取指定的寬高(width,height ),把所得圖像的每個像素顏色轉為int值,存入pixels。
至於參數stride,查了資料,發現看不太懂,於是便是沒有繼續深究,我們直接用就是了
我們需要一個線程來完成我們的計算像素,因為計算不能一直在UI線程裡面執行,可能會出現卡頓,當用戶抬起手指的時候,我們就啟動這個計算進程來計算用戶所擦除的像素點
本功能有些複雜,要想看得懂,需要瞭解 UI線程更新View的知識和java中進程部分知識,推薦看一下這篇子進程更新UI
private Runnable mRunnable = new Runnable() {
int[] pixels;
@Override
public void run() {
int w = mBitmap.getWidth();
int h = mBitmap.getHeight();
float wipeArea = 0;//擦除像素點計數,初始為0
float totalArea = w * h;//全部的像素點
pixels = new int[w * h];
/**
* pixels 接收點陣圖顏色值的數組
* offset 寫入到pixels[]中的第一個像素索引值
* stride pixels[]中的行間距個數值(必須大於等於點陣圖寬度)。可以為負數
* x 從點陣圖中讀取的第一個像素的x坐標值。
* y 從點陣圖中讀取的第一個像素的y坐標值
* width 從每一行中讀取的像素寬度
* height 讀取的行數
*/
Bitmap b = mBitmap;
b.getPixels(pixels, 0, w, 0, 0, w, h);
//for迴圈查找用戶擦除的像素點,為0則是擦除,wipeArea+1
for (int i = 0; i < totalArea; i++) {
if (pixels[i] == 0) {
wipeArea++;
}
}
//
if (wipeArea > 0 && totalArea > 0) {
int percent = (int) (wipeArea * 100 / totalArea);//計算比例
if (percent > 50) {
isClear = true;//isClear是之前聲明的全局變數,
postInvalidate();//子進程中調用此方法重繪View
}
}
}
};
上述代碼中有個for迴圈用來記錄擦除像素點,有些疑問,因為鴻洋大神用的不一樣,鴻洋大神使用的是下麵的嵌套迴圈
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
int index = i + j * w;
if (pixels[index] == 0) {
wipeArea++;
}
}
}
之後我們還需要改寫代碼,首先,是在觸摸事件中增加我們對用戶抬起手指的操作
case MotionEvent.ACTION_UP:
new Thread(mRunnable).start();
break;
之後,通過isClear這個變數來控制是否畫出路徑,onDraw
方法之中進行這樣的修改
protected void onDraw(Canvas canvas) {
canvas.drawText(message,mBitmap.getWidth()/2-mBackground.width()/2,getMeasuredHeight()/2+mBackground.height()/2,messagePaint);
if (!isClear){
drawPath();
canvas.drawBitmap(mBitmap, 0,0, null);
}
}
當canvas寫出了文字,之後就不畫遮蓋層了,這樣便是達到了清除遮蓋層的效果
這裡需要註意一下if中的條件,還要,isClear
還得用volatile
修飾,通俗的講就是加了個鎖,防止併發出現錯誤
2.遮蓋層繪製圖片
可能大家對這個功能很不屑,認為自己之前不是會了嗎,其實沒有那麼簡單,我自己嘗試的時候都出現了錯誤,經過搜索資料嘗試才達到效果。
先說下我遇到的問題
- 圖片只顯示一部分
- 畫筆清除不了圖片,畫的時候出現黑色的筆跡
第一個問題,我們可以通過Bitmap的靜態方法來解決
public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight,boolean filter)
傳入一個需要調整大小的bitmap對象,之後,長度和高度,最後一個參數傳入true
background = Bitmap.createScaledBitmap(background,width,height,true);//對bitmap進行縮放
第二個問題,因為我們使用的是雙緩衝技術繪圖,所以,我們需要將遮蓋層的圖片先繪製在mBitmap中去
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);//以獲得的寬高創建一個32位的bitmap
mCanvas = new Canvas(mBitmap);
mCanvas.drawBitamap(background,0,0,null);
3.回調介面
public interface onGuaCompleteListener{
void complete();
}
private onGuaCompleteListener mlistener;
public void setGuaCompleteListener(onGuaCompleteListener mlistener) {
this.mlistener = mlistener;
}
之後在onDraw
方法里添加回調
protected void onDraw(Canvas canvas) {
Log.d(TAG, "onDraw: 畫");
canvas.drawText(message,mBitmap.getWidth()/2-mBackground.width()/2,getMeasuredHeight()/2+mBackground.height()/2,messagePaint);
if (!isClear){
drawPath();
canvas.drawBitmap(mBitmap, 0,0, null);
}else if (mlistener!=null){
mlistener.complete();
}
}
當畫到百分之60的時候,就會將isClear的值變為true,同時,就會進入到else if中,回調完成刮獎的介面
我們到MainActivity中設置監聽器來監聽刮刮卡的完成操作,彈出一個Toast或者是對話框,我這裡簡單起見就直接彈出一個Toast
GuajiangView mView = (GuajiangView) findViewById(R.id.view);
mView.setGuaCompleteListener(new GuajiangView.onGuaCompleteListener() {
@Override
public void complete() {
Toast.makeText(MainActivity.this, "hello", Toast.LENGTH_SHORT).show();
}
});