**一、實現原理**
Paint.setXferMode();
a、繪制我們的圓形
b、setXferMode(SrcIn)
c、繪制矩形(正方形)圖片
**二、主要思想:**
將一個view設計成多層:背景層,含中獎信息等;
遮蓋層,用于刮獎,使用關聯一個Bitmap的Canvas
在該Bitmap上,使用它的canvas.drawPath的api來處理 手勢滑動(類似刮獎的動作)
使用paint.setXfermode 來進行消除手勢滑動區域
當刮開90%的時候會全部消失。
**三、代碼實現**
~~~
public class GuaGuaKa extends View
{
private Paint mOutterPaint;
private Path mPath;
private Canvas mCanvas;
private Bitmap mBitmap;
private int mLastX;
private int mLastY;
private Bitmap mOutterBitmap;
// -------------------------------
// private Bitmap bitmap;
private String mText;
private Paint mBackPaint;
/**
* 記錄刮獎信息文本的寬和高
*/
private Rect mTextBound;
private int mTextSize;
private int mTextColor;
// 判斷遮蓋層區域是否消除達到閾值
private volatile boolean mComplete = false;
/**
* 刮刮卡刮完的回調
*
*
*/
public interface OnGuaGuaKaCompleteListener
{
void complete();
}
private OnGuaGuaKaCompleteListener mListener;
public void setOnGuaGuaKaCompleteListener(
OnGuaGuaKaCompleteListener mListener)
{
this.mListener = mListener;
}
public GuaGuaKa(Context context)
{
this(context, null);
}
public GuaGuaKa(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public GuaGuaKa(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
TypedArray a = null;
try
{
a = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.GuaGuaKa, defStyle, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++)
{
int attr = a.getIndex(i);
switch (attr)
{
case R.styleable.GuaGuaKa_text:
mText = a.getString(attr);
break;
case R.styleable.GuaGuaKa_textSize:
mTextSize = (int) a.getDimension(attr, TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_SP, 22,
getResources().getDisplayMetrics()));
break;
case R.styleable.GuaGuaKa_textColor:
mTextColor = a.getColor(attr, 0x000000);
break;
}
}
} finally
{
if (a != null)
a.recycle();
}
}
public void setText(String mText)
{
this.mText = mText;
// 獲得當前畫筆繪制文本的寬和高
mBackPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
// 初始化我們的bitmap
mBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
// 設置繪制path畫筆的一些屬性
setupOutPaint();
setUpBackPaint();
// mCanvas.drawColor(Color.parseColor("#c0c0c0"));
mCanvas.drawRoundRect(new RectF(0, 0, width, height), 30, 30,
mOutterPaint);
mCanvas.drawBitmap(mOutterBitmap, null, new Rect(0, 0, width, height),
null);
}
/**
* 設置我們繪制獲獎信息的畫筆屬性
*/
private void setUpBackPaint()
{
mBackPaint.setColor(mTextColor);
mBackPaint.setStyle(Style.FILL);
mBackPaint.setTextSize(mTextSize);
// 獲得當前畫筆繪制文本的寬和高
mBackPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
}
/**
* 設置繪制path畫筆的一些屬性
*/
private void setupOutPaint()
{
mOutterPaint.setColor(Color.parseColor("#c0c0c0"));
mOutterPaint.setAntiAlias(true);
mOutterPaint.setDither(true);
mOutterPaint.setStrokeJoin(Paint.Join.ROUND);
mOutterPaint.setStrokeCap(Paint.Cap.ROUND);
mOutterPaint.setStyle(Style.FILL);
mOutterPaint.setStrokeWidth(20);
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
switch (action)
{
case MotionEvent.ACTION_DOWN:
mLastX = x;
mLastY = y;
mPath.moveTo(mLastX, mLastY);
break;
case MotionEvent.ACTION_MOVE:
int dx = Math.abs(x - mLastX);
int dy = Math.abs(y - mLastY);
if (dx > 3 || dy > 3)
{
mPath.lineTo(x, y);
}
mLastX = x;
mLastY = y;
break;
case MotionEvent.ACTION_UP:
if (!mComplete)
new Thread(mRunnable).start();
break;
}
if (!mComplete)
invalidate();
return true;
}
~~~
~~~
</pre>我們在ACTION_UP的時候就行計算,首先我們還是給大家灌輸下計算的原理,如果大家用心看了,應該知道我們所有的操作基本都在mBitmap,現在我們獲得mBItmap上所有的像素點的數據,統計被清除的區域(被清除的像素為0);最后與我們圖片的總像素數做個除法元算,就可以拿到我們清除的百分比了;不過,計算可能會是一個耗時的操作,具體速度跟圖片大小有關,所以我們決定使用異步的方式去計算:<pre name="code" class="java">
~~~
~~~
private Runnable mRunnable = new Runnable()
{
@Override
public void run()
{
int w = getWidth();
int h = getHeight();
float wipeArea = 0;
float totalArea = w * h;
Bitmap bitmap = mBitmap;
int[] mPixels = new int[w * h];
// 獲得Bitmap上所有的像素信息
bitmap.getPixels(mPixels, 0, w, 0, 0, w, h);
for (int i = 0; i < w; i++)
{
for (int j = 0; j < h; j++)
{
int index = i + j * w;
if (mPixels[index] == 0)
{
wipeArea++;
}
}
}
if (wipeArea > 0 && totalArea > 0)
{
int percent = (int) (wipeArea * 100 / totalArea);
Log.e("TAG", percent + "");
if (percent > 90)
{
// 清除掉圖層區域
mComplete = true;
postInvalidate();
}
}
}
};
@Override
protected void onDraw(Canvas canvas)
{
// canvas.drawBitmap(bitmap, 0 , 0, null);
canvas.drawText(mText, getWidth() / 2 - mTextBound.width() / 2,
getHeight() / 2 + mTextBound.height() / 2, mBackPaint);
if (!mComplete)
{
drawPath();
canvas.drawBitmap(mBitmap, 0, 0, null);
}
if (mComplete)
{
if (mListener != null)
{
mListener.complete();
}
}
}
private void drawPath()
{
mOutterPaint.setStyle(Style.STROKE);
mOutterPaint.setXfermode(new PorterDuffXfermode(Mode.DST_OUT));
mCanvas.drawPath(mPath, mOutterPaint);
}
/**
* 進行一些初始化操作
*/
private void init()
{
mOutterPaint = new Paint();
mPath = new Path();
mOutterBitmap = BitmapFactory.decodeResource(getResources(),
cn.zhilinghui.guaguaka.R.drawable.fg_guaguaka);
mText = "謝謝惠顧";
mTextBound = new Rect();
mBackPaint = new Paint();
mTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
22, getResources().getDisplayMetrics());
}
}
~~~
view的自定義控件:
~~~
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:hyman="http://schemas.android.com/apk/res/cn.zhilinghui.guaguaka"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<cn.zhilinghui.guaguaka.view.GuaGuaKa
android:id="@+id/id_guaguaka"
android:layout_width="300dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
hyman:text="¥500,0000"
hyman:textColor="#ff00f0"
hyman:textSize="30sp" />
</RelativeLayout>
~~~

- 前言
- 內存溢出的解決方案
- 安卓消息推送解決方案
- 語言識別和聊天機器人的實現
- 抽屜效果的實現(DrawerLayout和SlidingMenu的對比)
- 植物大戰僵尸經典開發步驟
- 屏幕適配全攻略
- 安卓圖像處理入門教程
- android開發常用工具箱
- java基礎知識總結
- 剖析軟件外包項目
- java基礎知識——網絡編程、IO流
- 安卓性能優化手冊
- 電商活動中刮刮卡的實現
- Android系統的安全設計與架構
- AsnycTask的內部的實現機制
- Android應用UI設計流程
- 數據結構與算法,每日一道
- html5全解析
- 深入解讀XML解析
- 新聞客戶端案例開發
- 細說Http協議
- win10+ubuntu雙系統安裝方案
- 隨機驗證碼實現案例
- 動態數組的實現案例
- 猜拳游戲案例
- 商業級項目——基金客戶端的架構設計與開發(上)