目录
目录.png效果展示
实现原理
实现原理通俗的讲就是利用Paint的setXfermode方法设置混合模式,设置的混合模式为PorterDuff.Mode.CLEAR即将手指移动的区域清除,清除后的区域为透明的,所以会将控件下面的刮奖结果显示出来。另外要注意的是在绘制之前需要保存Canvas状态,绘制完成后需要恢复Canvas状态。
代码展示
public class ScrapeView extends View {
private Paint mPaint;
private Path mPath;
private PointF mPointF;
public ScrapeView(Context context) {
super(context);
init();
}
public ScrapeView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public ScrapeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
setLayerType(LAYER_TYPE_SOFTWARE,null);//关闭硬件加速
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(20);
mPath = new Path();
mPointF = new PointF();
}
/**
* 修改高度
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec),measuredHeight(heightMeasureSpec));
}
/**
* 测量宽
* @param widthMeasureSpec
*/
private int measureWidth(int widthMeasureSpec) {
int result ;
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
if (specMode == MeasureSpec.EXACTLY){
result = specSize;
}else {
result = 200;
if (specMode == MeasureSpec.AT_MOST){
result = Math.min(result,specSize);
}
}
return result;
}
/**
* 测量高
* @param heightMeasureSpec
*/
private int measuredHeight(int heightMeasureSpec) {
int result ;
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);
if (specMode == MeasureSpec.EXACTLY){
result = specSize;
}else{
result = 200;
if(specMode == MeasureSpec.AT_MOST){
result = Math.min(result,specSize);
}
}
return result;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mPath.reset();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
mPointF.x = event.getX();
mPointF.y = event.getY();
mPath.moveTo(event.getX(),event.getY());
invalidate();
return true;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
mPath.quadTo(mPointF.x,mPointF.y,(mPointF.x+event.getX())/2,(mPointF.y+event.getY())/2);//贝赛尔曲线让路径更圆润
mPointF.x = event.getX();
mPointF.y = event.getY();
//下面这行代码依然可以实现效果(只是不够圆润)
// mPath.lineTo(event.getX(),event.getY());
invalidate();
break;
}
return super.onTouchEvent(event);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();//存储画布状态(离屏绘制)
mPaint.setColor(Color.GRAY);
mPaint.setMaskFilter(new BlurMaskFilter(20, BlurMaskFilter.Blur.NORMAL));//给卡片周围加上柔光效果
mPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(new RectF(0,0,getWidth(),getHeight()),mPaint);
mPaint.setMaskFilter(null);//清空MaskFilter,否则刮卡时也是模糊的效果
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));//利用混合模式将手指移动的区域(mPath的路径)清空
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(mPath,mPaint);
mPaint.setXfermode(null);//清除混合模式
canvas.restore();//恢复上面存储的画布状态
}
}
网友评论