先看下效果图
如何实现
1.初始化
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(80);
mPaint.setStrokeCap(Paint.Cap.ROUND);
//禁止硬件加速
setLayerType(View.LAYER_TYPE_SOFTWARE,null);
//初始化图片对象
mTxtBmp = BitmapFactory.decodeResource(getResources(),R.mipmap.result); //刮刮卡结果
mSrcBmp = BitmapFactory.decodeResource(getResources(),R.mipmap.eraser); //刮刮卡封面
mDstBmp = Bitmap.createBitmap(mSrcBmp.getWidth(),mSrcBmp.getHeight(),Bitmap.Config.ARGB_8888);
//初始化Path(贝塞尔曲线)
mPath = new Path();
2.监听触摸事件
重写onTouchEvent方法
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
return true;
}
对于ACTION_DOWN事件,记录下X和Y坐标,并将Path移动到该点作为起始点
mEventX = event.getX();
mEventY = event.getY();
mPath.moveTo(mEventX, mEventY);
对于ACTION_MOVE事件,先计算出目标点
float endX = (event.getX() - mEventX) / 2 + mEventX;
float endY = (event.getY() - mEventY) / 2 + mEventY;
然后,使用Path记录二阶贝塞尔曲线
mPath.quadTo(mEventX, mEventY, endX, endY);
最后,记录下Event的X和Y坐标,并赋值给mEventX和mEventY
mEventX = event.getX();
mEventY = event.getY();
接着,无论是ACTION_DOWN和ACTION_MOVE,都需要通知View重新进行绘制
invalidate();
3.重写Draw方法
首先,先绘制刮刮卡结果图像
canvas.drawBitmap(mTxtBmp, 0, 0, mPaint);
接着,使用离屏绘制
int layerID = canvas.saveLayer(0, 0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);
将Path绘制到刮刮卡结果图像上
Canvas dstCanvas = new Canvas(mDstBmp);
dstCanvas.drawPath(mPath, mPaint);
接着绘制刮刮卡结果图像
canvas.drawBitmap(mDstBmp, 0, 0, mPaint);
设置 模式 为SRC_OUT,取上层绘制非交集部分,交集部分变成透明
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
绘制刮刮卡封面图像
canvas.drawBitmap(mSrcBmp, 0, 0, mPaint);
结束离屏绘制
mPaint.setXfermode(null);
canvas.restoreToCount(layerID);
小结
如此,刮刮卡的效果就实现了,主要还是用到了Path和Xfermode离屏绘制,将封面图片和Path进行图片混合,并使Path经过的路线变透明,从而实现刮刮卡的效果。