自定义View实现刮刮卡界面:
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* 自定义一个刮刮卡view
* @description:
* @date 2015-12-3 上午9:27:06
*/
@SuppressLint(“DrawAllocation”)
public class ScratchCardView extends View {
private Paint mPaint;// 画笔
private Path mPath;// 绘制路径
private Canvas mCanvas;// 画面Canvas
private int mCurrentX;// 手指移动后X位置
private int mCurrentY;// 手指移动后Y位置
private Bitmap mTopBitmap;// 位于上层图片
private String mTextStr;// 卡片上的文字
private Paint mTextPaint;// 画文字的画笔
private Rect mTextRect;// 文字对应的矩形框Rect
private volatile boolean isFinish = false;// 判断遮盖层是否被用户消除达到一定的范围(阙值)
private OnScratchCardFinishListener mCardFinishListener;//刮完成后回调接口
public interface OnScratchCardFinishListener {// 图层刮完后回调接口
void onFinish(String result);
}
// 设置回调
public void setCardFinishListener(OnScratchCardFinishListener mCardFinish) {
this.mCardFinishListener = mCardFinish;
}
public ScratchCardView(Context context) {
this(context, null, 0);
}
public ScratchCardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initViewsParams();
}
public ScratchCardView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
/**
* 初始化相关数据及参数
* @description:
* @date 2015-12-3 上午9:26:48
*/
private void initViewsParams() {
mPath = new Path();
mPaint = new Paint();
mTextStr = "500万现金";
mTextPaint = new Paint();
mTextRect = new Rect();
}
private void setTextPaint() {
mTextPaint.setColor(Color.RED);// 设置颜色
mTextPaint.setStyle(Style.FILL);// 设置画笔样式为填充
mTextPaint.setTextSize(40);
mTextPaint.getTextBounds(mTextStr, 0, mTextStr.length(), mTextRect);// 获得当前文字的宽高信息
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();// 获取到宽度
int height = getMeasuredHeight();// 获取到高度
mTopBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);// 根据参数创建新位图
mCanvas = new Canvas(mTopBitmap);
// 设置绘画文字的画笔 参数
setTextPaint();
// 设置画笔参数
setBitmapPaint();
mCanvas.drawColor(Color.parseColor("#c0c0c0"));
}
private void setBitmapPaint() {
mPaint.setColor(Color.GREEN);// 设置颜色
mPaint.setAntiAlias(true);// 设置抗紧锯齿
mPaint.setDither(true);// 防抖动
mPaint.setStrokeJoin(Paint.Join.ROUND);// 设置图形结合处的样子
mPaint.setStrokeCap(Paint.Cap.ROUND);// 设置画笔的图形样式,如圆形样式
mPaint.setStyle(Style.STROKE);// 设置画笔样式为空心
mPaint.setStrokeWidth(20);// 设置画笔粗细
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
int x = (int) event.getX();// 当前x
int y = (int) event.getY();// 当前y
switch (action) {
case MotionEvent.ACTION_DOWN:
mCurrentX = x;
mCurrentY = y;
mPath.moveTo(mCurrentX, mCurrentY);// 移动Path
break;
case MotionEvent.ACTION_MOVE:
int dx = Math.abs(x - mCurrentX);
int dy = Math.abs(y - mCurrentY);
if (dx > 3 || dy > 3) {
mPath.lineTo(x, y);
}
mCurrentX = x;
mCurrentY = y;
break;
case MotionEvent.ACTION_UP:
new Thread(mCardRunble).start();//开启子线程进行计算
break;
default:
break;
}
invalidate();//主线程中调用invalidate()请求重绘View树,即draw()过程
return true;
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawText(mTextStr, getWidth() / 2 - mTextRect.width() / 2, getHeight() / 2 + mTextRect.height() / 2, mTextPaint);
if (!isFinish) {
mPaint.setXfermode(new PorterDuffXfermode(Mode.DST_OUT));// ProterDuffXfermode用法可以参考:http://www.2cto.com/kf/201504/388144.html
mCanvas.drawPath(mPath, mPaint);
canvas.drawBitmap(mTopBitmap, 0, 0, null);
}
else {
if (mCardFinishListener != null) {
mCardFinishListener.onFinish(mTextStr);
}
}
}
private Runnable mCardRunble = new Runnable() {
@Override
public void run() {
int w = getWidth();
int h = getHeight();
float wipeArea = 0;
float totalArea = w * h;
Bitmap bitmap = mTopBitmap;
int[] mpixels = new int[w * h];
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);// 获取百分比
if (percent > 60) {
isFinish = true;
postInvalidate();//子线程中调用invalidate()请求重绘View树,即draw()过程
}
}
}
};
}
在Activity中使用,关键是要回调刮奖完毕的回调接口OnScratchCardFinishListener中的方法:
public class MainActivity extends Activity {
private ScratchCardView mCardView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCardView = (ScratchCardView) findViewById(R.id.card_view);
mCardView.setCardFinishListener(new OnScratchCardFinishListener() {
@Override
public void onFinish(String result) {
Toast.makeText(MainActivity.this, result, Toast.LENGTH_LONG).show();//回调时把显示的文字也Toast出来!
}
});
}
布局很简单,就是加了一个我们自定义的ScrtchCardView: